Копировать только обычные файлы из одного каталога в другой

12

Я хотел бы скопировать содержимое каталога 1 в каталог 2. Однако я хотел бы копировать только файлы (а не каталоги) из моего каталога 1. Как я могу это сделать?

cp dir1/* dir2/*

тогда у меня все еще есть проблема с каталогами.

Кроме того, все мои файлы не имеют расширения, поэтому . не добьется цели

user1058398
источник
1
Не знаю, какое расширение имеет к этому отношение.
Ctrl-Alt-Delor
1
cp dir1/* dir2илиcp -t dir2 dir1/*
Ctrl-Alt-Delor
@ Richard Существует довольно распространенная привычка из мира DOS не использовать расширения для каталогов, которая до сих пор сохраняется до некоторой степени, заставляя некоторых людей предполагать, что если есть точка, то это не каталог, и наоборот.
Жиль "ТАК - перестань быть злым"
хорошо, но все еще не подходит.
Ctrl-Alt-Delor

Ответы:

18
cp dir1/* dir2

cpне будет копировать каталоги, если это явно не указано ( --recursiveнапример, см. man cp).

Примечание 1: cp скорее всего, выйдет с ненулевым статусом, но файлы все равно будут скопированы. Это может быть проблемой , когда цепочки команд на основе кодов выхода: &&, ||, if cp -r dir1/* dir2; then ...и т.д. (спасибо contrebis за свой комментарий по этому вопросу )

Примечание 2 : cpожидается, что последним параметром будет одно имя файла или каталога. *После имени целевого каталога действительно не должно быть подстановочных знаков . dir2\*будет расширяться оболочкой так же, как dir1\*. Неожиданные вещи будут происходить:

  • Если dir2пусто и зависит от вашей оболочки и настроек:
    • Вы можете просто получить сообщение об ошибке, что является лучшим вариантом.
    • dir2/*будет восприниматься буквально (поиск файла / каталога с именем *), что, вероятно, также приведет к ошибке, если она *не существует.
    • dir2/*он просто будет удален из команды полностью, оставив cp dir1/*. Который, в зависимости от расширения dir1/*, может даже уничтожить данные:
      • Если dir1/*соответствует только один файл или каталог, вы получите сообщение об ошибке cp.
      • Если dir1/*совпадает ровно два файла, один будет перезаписан другим ( Плохо ).
      • Если dir/*совпадает несколько файлов, а последнее совпадение равно a, вы получите сообщение об ошибке.
      • Если последнее совпадение dir/*является каталогом, все остальные совпадения будут перемещены в него.
  • Если dir2не пусто, это опять зависит:
    • Если последнее совпадение dir2/*является каталогом, dir1/*а другие совпадения dir2/*будут перемещены в.
    • Если последним совпадением dir2/*является файл, вы, вероятно, получите сообщение об ошибке, если не dir1/* соответствует только один файл.
Adaephon
источник
$ cp dir1/* dir2-> cp: dir1/isadir is a directory (not copied).Выход со статусом 1 для меня.
contrebis
1
Да, он тоже выходит со статусом 1. Но даже в этом cpслучае копируются ли файлы, совпадающие dir1/*на каждой проверенной мной системе: Arch Linux, Ubuntu 14.04, OpenBSD 3.9 и 5.5, SuSE Linux 8.1, FreeBSD 6.2, Solaris 8, 9 и 10 (где cpфактически завершается с кодом 2). Таким образом, это поведение не является новым (SuSE 8.1 с 2002 года) и не ограничивается Linux. cpвыходит с ненулевым кодом выхода, потому что он не может сделать все, что ему было сказано. Это не значит, что ничего не делает .
Adaephon
3
Конечно, я подумал, стоит отметить, потому что если вы объединяете команды вместе с &&этим, это может вызвать проблемы. Я пытался что-то вроде этого, хотя я не могу вспомнить контекст сейчас.
contrebis
Это не копирует скрытые файлы.
18:31
@felwithe Включение *скрытых файлов или включение скрытых файлов зависит от оболочки. Если *не содержит скрытых файлов, вы можете сопоставить их с .*. Обратите внимание , что это будет включать в себя .и ..на bashи , dashно не на zsh. В контексте этого ответа вы можете сойти с рук, cp dir1/* dir1/.* dir2потому что .и ..каталоги и не будут скопированы. zshтакже можно включить скрытые файлы с *(D).
Adaephon
7

Это оболочка, которая расширяет символы подстановки, а не команды. Итак, cp dir1/* dir2/*сначала расширяются два подстановочных знака, а затем вызывается cpрезультат. Это совсем не то, что вы, очевидно, ожидаете: в зависимости от того, сколько файлов уже есть dir2, dir2/*может быть расширен до одного или нескольких аргументов. Команда cpне знает, какие из ее аргументов были получены при расширении первого шаблона, а какие - при расширении второго шаблона. Ожидается, что его последним аргументом будет имя каталога назначения. Таким образом, чтобы скопировать все файлы из каталога dir1в каталог dir2, последний аргумент должен быть каталогом dir2:

cp dir1/* dir2

Так как *совпадает со всеми файлами, cpпытается скопировать все файлы. Это включает в себя каталоги: каталоги тоже файлы. Он пропускает каталоги, но сообщает об ошибке. Он копирует содержимое специальных файлов, таких как именованные каналы (что-то лучше записывать в них, или они cpбудут блокироваться) и т. Д.

Чтобы копировать только обычные файлы, вам нужно ограничить соответствие. В zsh вы можете использовать для этого квалификатор glob . :

cp dir1/*(.) dir2

У других оболочек этого нет. Вы можете использовать findкоманду для фильтрации по типам файлов. Предполагая, что вы используете не встроенный Linux или Cygwin:

find dir1 -maxdepth 1 -type f -exec cp -t dir2 {} +

В Linux, FreeBSD и OSX:

find dir1 -maxdepth 1 -type f | xargs -I {} cp {} dir2
Жиль "ТАК - перестань быть злым"
источник
Есть ли причина уточнить -maxdepth 1. Кроме того, есть ли способ рекурсивного копирования и сохранения исходной иерархии каталогов в целевом каталоге?
Абдулл
@Abdull Без -maxdepth 1, findкоманда превратилась бы в подкаталоги, чего здесь не хотелось. Если вы хотите скопировать все дерево каталогов , включая подкаталоги, это совершенно другой вопрос, и ответ на него намного проще: cp -a dir1 dir2.
Жиль "ТАК - перестань быть злым"
0

Ниже приведена команда для копирования файла из исходного каталога в целевой.

  1. Перейдите в исходную папку и напишите ниже команду:

    $ cp fileName destination directory path

Пример:

cp publichOT.sh  /data/home/useradmin
Тапан Дубей
источник