Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Копирование файла с полной структурой директорий (http://forum.oszone.net/showthread.php?t=347663)

Uragan66 16-01-2021 15:57 2946416

Копирование файла с полной структурой директорий
 
Доброго времени суток всем!
Никак не получается копирование файла с полной структурой папок. Вроде и не сложный вопрос, но перепробовал и Xcopy, Robocopy и просто Copy-Item, файл копируется без папок.
Собственно, к примеру, есть путь:
Код:

C:\papka\papka1\papka2\README.txt
Нужно скопировать файл README.txt на другой раздел, к примеру D, чтобы сохранилась вся структура, включая корневую директорию.
В директории papka2 могут быть и другие файлы и папки, но нужно скопировать только файл README.txt
В итоге на диске D должна получится такая структура:
Код:

papka
  papka1
    papka2
      README.txt

Буду премного благодарен за советы и подсказки.

Iska 16-01-2021 17:00 2946419

Ну, например, так:
Код:

$sSourceFile = 'C:\papka\papka1\papka2\README.txt'

$sDestPath = [System.IO.Path]::Combine('D:', (Split-Path -Path ([System.IO.Path]::GetDirectoryName($sSourceFile)) -NoQualifier))

New-Item -Path $sDestPath -ItemType Directory -Force | Out-Null
Copy-Item -Path $sSourceFile -Destination $sDestPath


Fors1k 16-01-2021 17:42 2946422

Код:

param(
   
$path  = "C:\papka\papka1\papka2\README.txt",
    $drive = "D"
)
cls

Copy $path (NI -F($drive+$path.Remove(0,1)))


Uragan66 16-01-2021 19:04 2946436

Iska, Fors1k, спасибо большое! Оба скрипта работают при копировании в корень диска. А что нужно добавить, чтобы копирование шло в определённую папку, например, J:\RESERV\ttv ?

Iska 16-01-2021 19:16 2946439

Цитата:

Цитата Uragan66
А что нужно добавить, чтобы копирование шло в определённую папку, например, J:\RESERV\ttv ? »

Uragan66, т.е., из «C:\papka\papka1\papka2\README.txt» получался бы «J:\RESERV\ttv\papka\papka1\papka2\README.txt»?

Попробуйте так (не проверялось):
Код:

$sDestPath = [System.IO.Path]::Combine('J:\RESERV\ttv', (Split-Path -Path ([System.IO.Path]::GetDirectoryName($sSourceFile)) -NoQualifier))
В коде коллеги Fors1k тоже просто подставить искомое и чуть изменить код:
Код:

    $drive = "J:\RESERV\ttv"

Copy $path (NI -F($drive+$path.Remove(0,2)))


Uragan66 16-01-2021 19:39 2946443

Цитата:

Цитата Iska
т.е., из «C:\papka\papka1\papka2\README.txt» получался бы «J:\RESERV\ttv\papka\papka1\papka2\README.txt»? »

да
Цитата:

Цитата Iska
Попробуйте так (не проверялось): »

так не хочет, копируется в корень диска
По второму коду отлично
Спасибо!

greg zakharov 16-01-2021 20:21 2946450

А позвольте полюбопытствовать для чего необходимо копирование папки на другой раздел? Может просто обойтись созданием символической ссылки?

Uragan66 16-01-2021 21:10 2946454

Цитата:

Цитата greg zakharov
для чего нужен копирование папки на другой раздел »

если немного подробнее, то копирование нужно перед заменой файлов в плеере SimpleTV. Периодически для него появляются патчи или просто требуется замена его скриптов. Но не всегда патчи удачны и приходится потом всё назад возвращать.
Можно было бы конечно просто бекапы файлов делать, но папка плеера и так немаленькая... Лучше уж их на другой диск скопировать. Ну и структура папок важна, дабы потом не путаться.

greg zakharov 16-01-2021 22:55 2946476

Цитата:

Цитата Uragan66
...Но не всегда патчи удачны и приходится потом всё назад возвращать.
Можно было бы конечно просто бекапы файлов делать, но папка плеера и так немаленькая...

Всё равно непонятно для чего нагружать винт ненужным копированием, когда есть SCM. Или у вас SSD? Но и тогда какой смысл "размазывать" данные по накопителю? Берёте какую-нибудь SCM, скажем, git, переходите в корневую папку:
Код:

git init
git add -a
git commit -am "контрольная точка с описанием"

А когда понадобится вернуться к одному из ранних состояний, просто делаете откат на нужную контрольную точку. А если еще папка синхронизирована с облаком, то тогда вообще всё шоколадно. Если не хочется заморачиваться с git, можно обойтись fossil - благо один единственный бинарник.

Iska 17-01-2021 08:51 2946517

Цитата:

Цитата Uragan66
так не хочет, копируется в корень диска »

А… Семён Семёныч… Там и первый код по факту работал некорректно.

Попробуйте так:
Скрытый текст
Код:

$sSourceFile = 'C:\papka\papka1\papka2\README.txt'

$sDestPath = Join-Path -Path 'J:\RESERV\ttv' -ChildPath (Split-Path -Path ([System.IO.Path]::GetDirectoryName($sSourceFile)) -NoQualifier)

New-Item -Path $sDestPath -ItemType Directory -Force | Out-Null
Copy-Item -Path $sSourceFile -Destination $sDestPath


Uragan66 21-01-2021 12:52 2947090

Цитата:

Цитата greg zakharov
когда понадобится вернуться к одному из ранних состояний, просто делаете откат на нужную контрольную точку »

greg zakharov, спасибо! Совет в копилку, пригодится на будущее... Но в данной задаче с плеером немного не подходит. Пользователи Simple Player часто делятся скриптами и бывает кому-то нужен именно старый скрипт. А их принято выкладывать в полной структуре папок. Да и самому может нужно будет что-то подправить в старом скрипте при его откате.
Цитата:

Цитата Iska
Попробуйте так »

Iska, спасибо большое! Этот код работает, файл копируется в нужную директорию.

YuS_2 21-01-2021 13:30 2947097

Uragan66,
вообще, смотрите в сторону утилиты robocopy, у неё достаточно широкий функционал, в том числе и копирование со структурой...

Но если таки необходимо на powershell:
script.ps1
Код:

<#
        .SYNOPSIS
                Копирование или псевдоперемещение файлов и каталогов с сохранением структуры

        .Description
                Скрипт предназначен для копирования или перемещения файлов из одного каталога
                в другой, при этом сохраняется вложенная структура каталогов. Фактически,
                перемещение не выполняется, вместо него работает копирование с последующим
                удалением скопированнных итемов.

        .Parameter Source
                Необязательный: Исходный каталог для выборки элементов. Указывается либо
                относительный, либо абсолютный путь.

        .Parameter Destination
                Необязательный: Целевой каталог. Указывается либо относительный, либо
                абсолютный путь.

        .Parameter Include
                Необязательный: маска(и) для включения файлов в выборку
       
        .Parameter Exclude
                Необязательный: маска(и) для исключения файлов из выборки

        .Parameter Delete
                Переключатель: Если указан, то будут удалены исходные файлы, включенные в выборку,
                рекурсивно

        .Parameter Emptydelete
                Переключатель: Если указан, то будут удалены пустые подкаталоги в исходном каталоге,
                рекурсивно
               
        .Example
                .\script.ps1 -sourc "D:\FOLDER1" -dest "d:\Folder2" -incl '*.pdf','*.txt' -excl '*_out.*' -del

                Это пример перемещения файлов по маскам  '*.pdf','*.txt' с исключением из выборки по маске
                '*_out.*', с последующим удалением исходных элементов. Пустые каталоги не удаляются.

        .Example
                .\script.ps1

                Это пример копирования/перемещения файлов/каталогов, с сохранением структуры, но
                по указанным в самом скрипте параметрам...

        .Notes
                Created By YuS
                Version: 1.00
#>
# requires v 3.0
param (
        [string]
        $source = ".\Folder1",
        [string]
        $destination = ".\Folder2",
        [string[]]
        $include = '*.*',
        [string[]]
        $exclude = '',
        [switch]
        $delete,
        [switch]
        $emptydelete
)
$src = gi -lit $source -force

# копирование файлов с сохранением структуры
dir -lit $src.fullname -inc $include -exc $exclude -rec -force|copy -d {
        $d = split-path $_.fullname.replace("$($src.fullname)",$destination)
        if (!(test-path -lit $d)){md $d -force} else {$d}
} -force #-whatif

if ($delete) {
        # удаляем все скопированные файлы
        dir -lit $src.fullname  -inc $include -exc $exclude  -rec -force -file|
        del -force -rec
}
if ($emptydelete) {
        # удаляем пустые каталоги
        dir -lit $src.fullname -rec -dir -force|sort{$_.fullname.length} -des|%{
                if((dir -lit $_.fullname -rec -force) -eq $null){
                        del -lit $_.fullname -force
                }
        }
}


greg zakharov 22-01-2021 12:35 2947227

Цитата:

Цитата Uragan66
Пользователи Simple Player часто делятся скриптами и бывает кому-то нужен именно старый скрипт. А их принято выкладывать в полной структуре папок.

Вы слышали про такую штуку, как виртуальная катологизация?

Uragan66 22-01-2021 16:49 2947274

Цитата:

Цитата YuS_2
Но если таки необходимо на powershell »

YuS_2, спасибо! Скрипт хороший. Но для моей задачи не совсем подходит, мне нужно копировать конкретный файл/файлы, не затрагивая при этом другие файлы с таким же расширением, а в Вашем скрипте копирование идёт по маске.
Цитата:

Цитата greg zakharov
Вы слышали про такую штуку, как виртуальная катологизация? »

честно говоря, только в общих чертах. Но, думаю, это не совсем подойдёт... Если подойдёт мне, то может не подойти другим пользователям плеера. Скрипты то для этого и выкладываются в полной структуре папок, что большинство пользователей не знает куда их ложить, многие и не хотят узнавать, увы... А уж с виртуальной катологизацией то точно никто не захочет разбираться и вникать в это, к сожалению.

YuS_2 22-01-2021 21:38 2947316

Цитата:

Цитата Uragan66
копирование идёт по маске. »

полное имя файла с расширением, тоже может быть маской... конечно, если файлов с одинаковыми именами больше одного, то скопированы будут все... это единственная проблемка.
А, да, есть ещё одна "неприятность" - в powershell 5.1, при использовании параметра -literalpath, параметр -include не работает, но его можно заменить на параметр -filter, либо воспользоваться крайней версией powershell, т.е. способ обхода бага есть.


Время: 13:04.

Время: 13:04.
© OSzone.net 2001-