Команда cp: правильное копирование папок с файлами в *nix
В этой статье будут раскрыты некоторые неочевидные вещи связанные с использованием 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 в очень длинную командную строку наподобие:
cp -a /souce/a /source/b /source/c …… /target
На длину командной строки есть ограничение, которое мы можем узнать используя команду:
Получим максимальную длину командной строки в байтах:
…. Maximum length of command we could actually use: 2089314 ….
Итак, давайте будем обходиться вовсе без 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 имеет значение. Если перепутать, то получите полную белиберду: направление копирования поменяется.
Благодарности:
- Компании RUVDS.COM за поддержку и возможность публикации в своем блоге на Хабре.
- За изображение TripletConcept. Картинка очень большая и детальная, можно открыть в отдельном окне.
Скопировать структуру папок linux
Собственно хочется скопировать на другой диск полную структуру одного каталога, в нем примерно тысяча подкаталогов. Собственно нужна только структура, файлики сами не нужны.
Есть ли какая команда?
>
>Собственно хочется скопировать на другой диск полную структуру одного каталога, в нем
>примерно тысяча подкаталогов. Собственно нужна только структура, файлики сами не нужны.
>
>Есть ли какая команда?какой нить язык + какая нить рекурсивная функция
find -type d даст тебе список каталогов, а создавать можешь как душе угодно — хоть xargs mkdir с нужым параметром, хоть файло после парсить со списком этих каталогво.
>
>Собственно хочется скопировать на другой диск полную структуру одного каталога, в нем
>примерно тысяча подкаталогов. Собственно нужна только структура, файлики сами не нужны.
>
>Есть ли какая команда?find /where/to/search -type d | cpio -pvdm /where/to/copy
>>
>>Собственно хочется скопировать на другой диск полную структуру одного каталога, в нем
>>примерно тысяча подкаталогов. Собственно нужна только структура, файлики сами не нужны.
>>
>>Есть ли какая команда?
>
>
>find /where/to/search -type d | cpio -pvdm /where/to/copyСПАСИБО! все так и сделал, все ОК 🙂
Архив | Удалить | Индекс форумов | Темы | Пред. тема | След. тема |
Оцените тред (1=ужас, 5=супер)? [ 1 | 2 | 3 | 4 | 5 ] |
How to copy in bash all directory and files recursive?
SourceDir contains also sub-folders. Problem that in DestFolder not only all tree, but in up level all another levels and files. How to fix ?
4 Answers 4
cp -r ./SourceFolder ./DestFolder
So, to clarify, capital -R option will copy the root dir again; small -r option keeps the root paths the same.
cp is not a bash command but a separate executable, so it is system-specific. True bash commands on the other hand are the same across operating systems.
I had to add a slash at the end of my source folder. Not sure why. I was using build vars too. cp -r «$CONFIG_PATH/» «$CODESIGNING_FOLDER_PATH»
cp -r ./SourceFolder ./DestFolder
code for a copy with success result
cp -rv ./SourceFolder ./DestFolder
code for Forcefully if source contains any readonly file it will also copy
cp -rf ./SourceFolder ./DestFolder
also try this cp -r ./dist/* ./out ;
this command will copy dist/* files to out dir;
@SherylHohman It’s different because he put a /* on the end of the source folder. I don’t know why that matters though.
this response instead of copying the entire folder copies content of the source folder into the destination (./out) folder
You might find it handy to keep your attributes set
cp -arf ./SourceFolder ./DestFolder
cp -arf . throws the error «cp: the -R and -r options may not be specified together.» Changing it to cp -af . solves it. I’m not sure if it’s a typo on your end of if cp -arf . actually worked for you, but I hope this helps in case anyone is getting the same error. Reference: stackoverflow.com/a/32695418/5810737