С копирование файла с заменой

Обновлено: 07.07.2024

В этой статье будут раскрыты некоторые неочевидные вещи связанные с использованием wildcards при копировании, неоднозначное поведение команды cp при копировании, а также способы позволяющие корректно копировать огромное количество файлов без пропусков и вылетов.

Допустим нам нужно скопировать всё из папки /source в папку /target.

Первое, что приходит на ум это:


Сразу исправим эту команду на:


Ключ -a добавит копирование всех аттрибутов, прав и добавит рекурсию. Когда не требуется точное воспроизведение прав достаточно ключа -r .

После копирования мы обнаружим, что скопировались не все файлы — были проигнорированы файлы начинающиеся с точки типа:

.profile
.local
.mc
и тому подобные.

Почему же так произошло?

Потому что wildcards обрабатывает shell ( bash в типовом случае). По умолчанию bash проигнорирует все файлы начинающиеся с точек, так как трактует их как скрытые. Чтобы избежать такого поведения нам придётся изменить поведение bash с помощью команды:


Чтобы это изменение поведения сохранилось после перезагрузки, можно сделать файл wildcard.sh c этой командой в папке /etc/profile.d (возможно в вашем дистрибутиве иная папка).

А если в директории-источнике нет файлов, то shell не сможет ничего подставить вместо звёздочки, и также копирование завершится с ошибкой. Против подобной ситуации есть опции failglob и nullglob . Нам потребуется выставить failglob , которая не даст команде выполниться. nullglob не подойдёт, так как она строку с wildcards не нашедшими совпадения преобразует в пустую строку (нулевой длины), что для cp вызовет ошибку.

Однако, если в папке тысячи файлов и больше, то от подхода с использованием wildcards стоит отказаться вовсе. Дело в том, что bash разворачивает wildcards в очень длинную командную строку наподобие:


На длину командной строки есть ограничение, которое мы можем узнать используя команду:


Получим максимальную длину командной строки в байтах:


Получим что-то типа:


Итак, давайте будем обходиться вовсе без wildcards.

Давайте просто напишем


И тут мы столкнёмся с неоднозначностью поведения cp . Если папки /target не существует, то мы получим то, что нам нужно.

Однако, если папка target существует, то файлы будут скопированы в папку /target/source.

Не всегда мы можем удалить заранее папку /target, так как в ней могут быть нужные нам файлы и наша цель, допустим, дополнить файлы в /target файлами из /source.

Если бы папки источника и приёмника назывались одинаково, например, мы копировали бы из /source в /home/source, то можно было бы использовать команду:


И после копирования файлы в /home/source оказались бы дополненными файлами из /source.

Такая вот логическая задачка: мы можем дополнить файлы в директории-приёмнике, если папки называются одинаково, но если они отличаются, то папка-исходник будет помещена внутрь приёмника. Как скопировать файлы из /source в /target с помощью cp без wildcards?

Чтобы обойти это вредное ограничение мы используем неочевидное решение:


Те кто хорошо знаком с DOS и Linux уже всё поняли: внутри каждой папки есть 2 невидимые папки "." и "..", являющиеся псевдопапками-ссылками на текущую и вышестоящие директории.

  • При копировании cp проверяет существование и пытается создать /target/.
  • Такая директория существует и это есть /target
  • Файлы из /source скопированы в /target корректно.

Поведение этой команды однозначно. Всё отработает без ошибок вне зависимости от того миллион у вас файлов или их нет вовсе.

Выводы

Если нужно скопировать все файлы из одной папки в другую, не используем wildcards, вместо них лучше использовать cp в сочетании с точкой в конце папки-источника. Это скопирует все файлы, включая скрытые и не завалится при миллионах файлов или полном отсутствии файлов.

Послесловие

vmspike предложил аналогичный по результату вариант команды:

ВНИМАНИЕ: регистр буквы T имеет значение. Если перепутать, то получите полную белиберду: направление копирования поменяется.
Благодарности:

Наведите курсор на файл, правой кнопкой мыши выберите: "свойства", затем, в открывшемся окне вверху, выберите вкладку "Предыдущие версии" и верните файл в исходное состояние.

P.S. В зависимости от Вашей операционной системы, для таких манипуляций с файлами Вам наверняка понадобятся "права администратора".

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

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


Для восстановления заменённого файла достаточно в контекстном меню выбрать пункт "Восстановить прежнюю версию".


Чем меньше времени прошло с момента перезаписи, тем больше шансов на восстановление, так как постоянно происходит обновление резервных копий.

Также можно настроить утилиту "Архивация и восстановление".

Имеется возможность восстановления предыдущей версии и с помощью специальных программ, например, WinHex.


Пару дней назад столкнулся с одной проблемой, после обработки ОЧЕНЬ большого количества фотографий с помощью софта, он ложил все файлы в одну папку.

Хоть изначально в программе и стоит функция перезаписи файлов оригинала на обработанный, но работает функционал криво и заменяет не все файлы.

Вариантов оставалось не много, либо искать другой софт для такой же обработки или же искать решение по переносу файлов в свои папки.

Для визуального представления, смотрите пример:

Есть Одна папка (/photo-start/), в которой вложено более 100 папок (/photo-start/name1/name2/2010/) , после обработка все фотографии/файлы были помещены в папку /finish-photo/

В ручную переносить тысячи файлов по папкам, это адская работа и пришлось искать автоматическое решение проблемы, чтобы с папки с обработанными файлами, перенести все данные в изначальное место их расположения.

Твиттер подсказал решение и дал надежду решить эту проблему:

@vasilenkolife проще было их после обработки кидать в свои папки. А теперь, наверное, только bash-скрипт писать с find.

Так как с bash я не силен, то решил поискать скрипт/софт который уже возможно написан. Но, ничего талкового не нашел, все работало не так как нужно и заменяло не все файлы (возможно из названий на русском)

Через пару минут поиска нашел другой простой способ замены файлов с сохранением иерархии папок:

Замена вашего файла на компьютере довольно распространена. Это может произойти случайно или вы могли бы заменить его, только чтобы узнать, что в вашем старом файле есть некоторые вещи.

Независимо от того, был ли это случайным или если он был преднамеренным, если вы заменили свой файл и плохо нуждаетесь в своем старом файле, тогда не беспокойтесь. Вы по-прежнему можете восстановить старый файл.

Откройте «Панель управления» вашего компьютера. Нажмите на меню «Пуск» и найдите «Панель управления».

Нажмите на это и, когда откроется окно «Панель управления», выберите «Производительность и обслуживание». После того, как вы нажмете на это, нажмите «Резервное копирование данных».

После нажатия «Резервное копирование данных» выберите «Восстановить файлы и настройки», затем нажмите кнопку «Далее». Появится окно со списком. Установите флажки для файлов, которые вы хотите восстановить, затем нажмите «Закрыть». Файлы, на которые вы нажали, теперь возвращены на ваш компьютер.

Этот параметр доступен только для компьютеров, на которых установлена резервная копия. Вы можете проверить, включен ли параметр резервного копирования, ища имя вашего файла с расширением «.wbk».

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

В Интернете существует множество внешних программ резервного копирования / восстановления. Некоторые программы бесплатны, хотя есть некоторые программы, которые вам придется покупать. Вы можете проверить Bounce Back Ultimate или Glary Utilities.

Установите программу.

После загрузки программного обеспечения вы должны установить его на свой компьютер. Обязательно следуйте всем инструкциям, чтобы программа работала.

Запустите программу.

После установки программы запустите программу. Дважды щелкните значок рабочего стола или откройте программу для ее запуска.

Восстановите свои файлы.

Вы найдете вариант, который позволит вам восстановить ваши файлы. Если у вас есть Bounce Back Ultimate, просто нажмите «восстановление одной кнопкой», чтобы восстановить замененные файлы.

Если у вас есть Glary Utilities, перейдите на вкладку «Модули», затем нажмите «Конфиденциальность и безопасность». Нажмите «File Undelete», затем откроется новое окно. Выберите место, где был сохранен последний файл, затем нажмите «Сканировать». Glary Utilities затем сканирует местоположение и восстанавливает все удаленные файлы. Сохраните файл под новым именем файла, чтобы сохранить его.

Всегда лучше включить функцию резервного копирования и восстановления, так как это упростит восстановление файлов для замененных файлов.

Но если вы отключили этот параметр, вы всегда можете использовать программы восстановления файлов для восстановления ваших файлов. Вот почему в следующий раз, когда вы случайно заменили свой файл, вам не нужно начинать с нуля, потому что вы можете легко восстановить его.

И в данном посте я рассмотрю замену и копирование файлов через командную строку, а именно, утилиты COPY и REPLACE. Но сперва, как всегда немого лирики.

замена и копирование файлов через командную строку

Пожалуй, любой программист сталкивался с вопросом написания функции для копирования каталога с файлами. Как правило, эти задачи решались при использовании рекурсии. В былые времена, не было мышки и правого клика со вкладкой «копировать, вырезать, вставить», да и синий Волков не сразу появился. Это теперь все так привычно, сидишь за клавиатурой, втыкаешь в зеленое поле Винды, клик туда, клик сюда, и все, задачу решил. Но, бывали и трудные ситуации, когда приходилось прибегать к синему менеджеру. Как не странно, но командная строка и ее утилиты от версии к версии меняют свой вид, Есть даже целый набор утилит типа PsUtils, которые эффективней стандартных ДОСовских. Логический вопрос, кому это все надо! Какой смысл изобретать современного динозавра, йоп те! С другой стороны, такова наша природа человеческая, мы готовы даже велосипед снова изобрести, лишь бы занять свой ум.

Командная строка COPY

Данный шедевр человеческой мысли позволяет произвести копирование (copy) через командную строку файла или файлов или даже их конкатенацию (объединение). Для решения подобных задач север сценариев Windows Script Host предоставляет в распоряжение метод CopyFile объекта FileSystemObject. Синтаксис утилиты командной строки copy, довольно устрашающий:

COPY [/D] [/V] [/N] [/Y | /-Y] [/Z] [/A | /B] источник [/A | /B] [+ источник [/A | /B] [+ . ]] [результат [/A | /B]]

/D – указывает на возможность создания зашифрованного файла.

/Y | /-Y – если выбран первый параметр, то будут отсутствовать запросы системы на подтверждение во время копирования (проще говоря, если придется топкой 1000 файлов копировать, то на каждый не будет выпрыгивать надоедливое “а вы уверены, или, может, другу позвоните?”), понятно, что второй параметр как раз то включает запрос подтверждения.

/Z – позволяет копировать данные по сети, кстати, в предыдущих вариантах данной утилиты этого ключа не наблюдалось.

/А – указывает, что файл является текстовым, если мы укажем данный параметр, то копирование прервется на метке конца файла ASCII код 26.

Если же данный параметр указан в самом конце, то эффект совсем другой. Произойдет полное копирование документа, но в копии будет добавлена метка конца файла если ее не было. Как результат, можете попробовать поэкспериментировать с pdf документом (my_file.pdf – размер документа составляет 247217 байт):

copy my_file.pdf/A new_file.pdf – на выходе мы получим документ new_file.pdf размером в 2538 байт.

/B – данный ключ идет по умолчанию и указывает, что файл является бинарным. То есть, происходит копирование всего документа.

/V – данный параметр включает проверку правильности копирования, сравнивая данные после завершения процедуры.

И так командная строка, копирование файлов и парочка примеров:

Копирование через командную строку файла 123.txt из текущего каталога в каталог D:\NEW под тем же именем:

COPY 123.txt D:\NEW

Копирование файла 123.txt из текущего каталога в каталог D:\NEW под новым именем new.txt:

COPY 123.txt D:\NEW\new.txt

Копирование всех документов с расширением txt с диска D:\ в каталог My Data на диске C:

COPY D:\*.txt "С:\My Data"

Допустим, мы находимся в каталоге D:\NEW и нам надо копирнуть в него все данные из каталога C:\DATA, в таком случае достаточно прописать следующий синтаксис:

COPY C:\DATA *.*

Используя командную строку, копируемые файлы можно склеить. Для этих целей достаточно использовать знак плюса «+», например:

COPY 1.txt +2.txt 3.txt– в данном примере содержимое документов 1.txt и 2.txt было объединено в 3.txt. Стоит помнить, что по дефолту, утилита COPY воспринимает данные как текстовые.

Вот пример с двоичными данными:

COPY /В *.dat all.dat – в данном варианте все данные с расширением dat из текущей папки были объединены в один файл all.dat.

Вообще, используя символ плюса «+» и мысли типа «а что если», можно проделать парочку экспериментов. Также стоит помнить ряд моментов:

Если название целевого объекта совпадает с одним из копируемых (кроме первого), то исходное содержимое целевого объекта будет утеряно.

Если имя целевого объекта опущено, то в его качестве будет использован первый объект из списка:.

COPY l.txt+2.txt – тут мы добавили к содержимому первого объекта содержимое второго.

COPY 1.txt +,, – данная конструкция позволяет присвоить объекту 1.txt текущую дату без его модификации.

Утилита COPY по своему первенству содержит ряд недостатков:

  • нельзя производить копирование файлов через командную строку с атрибутами скрытый или системный, а также системных и с атрибутом «Только для чтения».
  • обрыв всего процесса копирования при встрече с объектом, который в данный момент не поддается копированию.

В связи с такими неудобствами, умные люди подумали, и прибавили букву Х к названию COPY, чем решили массу проблем, создав утилиту XCOPY.

Командная строка REPLACE

Фактически, отличие данной утилиты в том, что она умеет заменять данные. Синтаксис довольно простой и понятный:

REPLACE [диск1:][путь1]имя_файла [диск2:] [путь2] [/А] [/Р] [/R] [/W]

REPLACE [диск1:][путь1]имя_файла [диск2:] [путь2] [/Р][/R][/S][/W][/U]

[диск1:] [путь1]имя_файла – определяем местонахождении копируемого объекта, или объектов.

[диск2:] [путь2] — определяем местонахождении объекта-результата. Как видно, имена замещаемых объектов задавать нельзя.

/А – добавляем в каталог-результат только новые объекты из каталога-результата (без перезаписи). Этот ключ нельзя использовать с ключами /S и / U.

/Р – выводится запрос на подтверждение перед заменой целевого или добавлением исходного файла.

/R – замещение не только обычных, но и защищенных от записи документов.

/S – позволяет производить поиск по всем подкаталогам целевого каталога и заменять файлы с совпадающими именами. Этот ключ нельзя использовать совместно с ключом /А. Поиск в каталогах, заданных параметром путь1, не производится.

/W – ожидание вставки диска перед началом выполнения

/U – режим обновления, то есть будут заменены только те объекты, которые имеют более раннюю дату модификации. Несовместимость с ключом /A.

Replace D:\Data\my_file.txt D:\Work – в папке Work заменяем файл my_file.txt на D:\Data\my_file.txt

При копировании файлов через командную строку посредством утилиты REPLACE, отсутствует возможность обновления скрытых или системных файлов. Для этого надо предварительно сменить их атрибуты.

Спасибо за внимание. Автор блога Владимир Баталий

date

13.05.2020

directory

PowerShell

comments

комментариев 6

PowerShell командлет Copy-Item используется для копирования файлов между локальными, сетевыми каталогами или между компьютерами по сети через WinRM. Командлет Copy-Item предоставляет большое количество опций, которые можно использовать в разных сценариях копирования файлов и каталогов (по своим возможностям этот командлет почти не уступает утилите robocopy). Например:

  • перезапись файлов (override)
  • фильтрация по имени/шаблону
  • исключение по имени/шаблону
  • Verbose режим
  • Копирование файлов с/на удаленные компьютеры

Начнем с простых примеров использования Copy-Item и будем переходить к более сложным.

Копирование файлов и каталогов

Чтобы скопировать один файл 1.txt из каталога C:\SourceFolder\ в F:\DestFolder\, выполните:

Copy-Item -Path "C:\SourceFolder\1.txt" -Destination "F:\DestFolder\1.txt"

Можно использовать сокращенный синтаксис командлета, пропустив указание параметров Path и Destination:

cpi "C:\SourceFolder\1.txt" "F:\DestFolder\1.txt"

Теперь скопируем каталог C:\SourceFolder\folder в F:\DestFolder\folder. В папке folder находится файл 1.txt. Обратите внимание что без ключа –Recurse, папка folder копируется без содержимого:

Copy-Item -Path "C:\SourceFolder\folder" -Destination "F:\DestFolder\folder" -Recurse

С помощью Copy-Item также можно просто объединить файлы из несколько директорий в одну (слияние директории), для этого нужно перечислить директории в ключе –Path:

Copy-Item -Path "C:\SourceFolder\*", "C:\SourceFolder2\*", "C:\SourceFolder3\*" -Destination "F:\DestFolder\"

Копирование с заменой и копирование с заменой read-only файлов

copy-item DirectoryExists

Для перезаписи файла с атрибутом read-only, нужно использовать ключ -Force. Если его не использовать, вы получите ошибку “отказано в доступе по пути… CopyFileInfoItemUnauthorizedAccessError”.

copy-item CopyFileInfoItemUnauthorizedAccessError

Чтобы скопировать файл с перезаписью файла с read-only атрибутом используйте параметр Force.

Copy-Item -Path "C:\SourceFolder\1.txt" -Destination "F:\DestFolder\1.txt" -Force

Совет. Чтобы не путаться, ключ –Force можно рассматривать как ключ для копирования с заменой.

Чтобы Copy-Item скопировал файлы из одной папки в другую без замены существующих файлов, можно использовать этот простой скрипт

Copy-Item (Join-Path "C:\SourceFolder\" "*") "F:\DestFolder\" -Exclude (Get-ChildItem "F:\DestFolder\") -Recurse

Этот скрипт скопирует все файлы и папки из C:\SourceFolder в F:\DestFolder без замены файлов уже существующих в F:\DestFolder

Копирование с фильтрацией по шаблону

С помощью Copy-Item можно скопировать файлы/директории выбранные с помощью wildcard символа * или с помощью символа ?. Также поддерживаются некоторые регулярные выражения

Для примера возьмём такую структуру файлов:

source

Выполним копирование командой:

Copy-Item -Path "C:\SourceFolder\fol*" -Destination "F:\DestFolder\"

Результат в F:\DestFolder\

copy-item replace

Теперь чистим папку назначения и выполняем:

Copy-Item -Path "C:\SourceFolder\folder1" -Destination "F:\DestFolder\"

result

Папка без цифры в окончании не скопировалась, потому что folder1 подразумевает что после folder будет как минимум еще 1 символ между 0 и 3

Исключение файлов при копировании

С помощью ключа –Exclude можно исключить файлы при копировании. Например, следующай команда скопирует все файлы кроме файлов с расширением txt.

Copy-Item -Path "C:\SourceFolder\*" -Destination "F:\DestFolder\" -Recurse -Force -Exclude "*.txt"

Аналогичным же образом можно применить ключ –Include, например

Copy-Item -Path "C:\SourceFolder\*" -Destination "F:\DestFolder\" -Recurse -Force -Include "*.txt"

Скопирует только txt файлы. Хотя для простоты гораздо удобнее использовать при копировании вид -Path "C:\SourceFolder\*.txt" .

Копирование файлов на удаленный компьютер по сети

Copy-File может копировать не только по SMB протоколу, но и через WinRM (WSMan).

Создайте новую сессию с компьютером testnode1 и выполните копирование в её контексте:

$session = New-PSSession -ComputerName testnode1
Copy-Item -Path "C:\SourceFolder\*" -ToSession $session -Destination "C:\SourceFolder\" -Recurse -Force

Эта команда скопирует файлы с локального компьютера из директории C:\SourceFolder на компьютер testnode1 в C:\SourceFolder\.

Примечание. Доступность WSMan на удаленном компьютере можно проверить с помощью командлета Test-WSMan.

Test-WSMan -ComputerName testnode1

Test-WSMan

Если WSMan не настроен, вы можете выполнить его быструю конфигурацию. Для этого откройте командную строку с правами администратора и выполните winrm quickconfig

winrm quickconfig

Также можно копировать и через обычные сетевые SMB шары, для этого просто используйте UNC формат сетевого пути.

Copy-Item -Path "C:\SourceFolder\*" -Destination "\\testnode1\C$\copy_tutorial\"

Можно скопировать файл с удаленного компьютера. Принцип такой же, как и при копировании файлов на удаленный компьютер, за исключением параметра –ToSession, вместо него нужно использовать –FromSession:

$session = New-PSSession -ComputerName testnode1
Copy-Item -FromSession $session -Path "C:\SourceFolder\*" -Destination "F:\DestFolder\" -Recurse -Force

Эта команда скопирует содержимое папки C:\SourceFolder\ с компьютера testnode1 на локальный компьютер в директорию F:\DestFolder

Ключ PassThru

Командлет Copy-Item (как и многие другие командлеты PowerShell) не возвращает результатов в консоль. Параметр PassThru применяется скриптах, или для лог-файлов, когда нужно получить список скопированных файлов и работать с ним дальше. Рассмотрим пример

$items = Copy-Item -Path "C:\SourceFolder\*" –Destination "\\testnode1\C$\copy_tutorial\" -PassThru

Переменная $items будет содержать список скопированных файлов, с которым вы можете работать дальше.Это значит что вы можете напрямую работать с этими файлами. Например выполнив команду Remove-Item $items[0] , вы удалите директорию folder.

copy-item passthru

Ключ Verbose

При использовании ключа -Verbose вы получите подробный лог операций копирования. Например, вывод команды

Copy-Item -Path "C:\SourceFolder\*.txt" -Destination "F:\DestFolder\" -Recurse -Force -Verbose

copy-item verbose лог

Несколько полезных скриптов с Copy-Item

Скопировать только файлы:

Get-ChildItem "C:\SourceFolder" -File -Recurse | Copy-Item -Destination "F:\DestFolder"

Скопировать структуру папок, без файлов:

$path = Get-ChildItem "C:\SourceFolder" -Recurse | ?
$dest = "F:\DestFolder\"
$parent = $path[0].Parent.Name
$path | foreach $_.FullName -match "$parent.+"
New-Item -ItemType directory ($dest + $Matches[0])
>

Copy-Item очень простой и удобный в использовании командлет PowerShell для выполнения операций копирования и перемещения файлов. В сочетании с другими инструментами PowerShell, Copy-Item также является мощным инструментом для написания скриптов.

Читайте также: