Я научился использовать команду find отдельно для поиска файлов и каталогов, однако когда дело доходит до выполнения каких-либо действий с файлами/папками, я теряюсь.
Дана следующая команда:
find . -type f -iname "*.cr2"
Если я хочу скопировать найденные выше файлы в новый каталог, я бы, естественно, подумал, что нужно использовать copy( cp
) и pipe |
.
find . -type f -iname "*.cr2" | cp \destination_directory
Для меня это означало бы, что все мои фотографии со всего диска будут размещены в одной папке и будут готовы к организации.
Однако люди продолжают говорить мне, что нужно использовать -exec
параметр, поэтому у меня вопрос: как узнать, когда следует передавать данные по конвейеру |
, а когда использовать -exec
команду, как показано ниже?
find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;
РЕДАКТИРОВАТЬ
Предложенное решение (ниже) копирует только файлы, имена которых уникальны. и оно говорит, что cp не будет копировать file.txt и заменять на file.txt. В случае, если вы копируете много файлов и не знаете, будут ли файлы с таким же именем, как вы можете скопировать что-то и сказать переименовать его, если имя файла существует?
Предлагаемое решение
find . -type f -iname "*.txt" -print0 | xargs -0 cp -t /home/josh/Documents/copy/
/home/josh/documents/copy — это каталог, в который я хочу переместить данные.
решение1
В ваших предположениях есть ошибки, но сначала немного предыстории:
Вам следует различать два варианта использования -exec
:
- с
\;
будет{}
заменен одним найденным элементом - при
+
этом{}
будет заменено множеством элементов (столько, сколько может вместить командная строка).
Поэтому ваш пример -exec
использования вызывает столько cp
команд, сколько элементов найдено find
.
Использование find ... -exec cmd {} ... +
аналогично по эффективности передаче выходных данных find в команду, обрабатывающую несколько входных имен.
Вам также следует принять во внимание, что -exec
отлично обрабатывает имена файлов/пути с пробелами, но когда вы передаете вывод из find в другую программу, это может вызвать проблемы. Поэтому некоторым программам, которые ожидают список имен файлов из stdin, можно предоставить возможность разделить эти имена файлов NUL (часто -0
или --null
). И find
имеет и возможность передать их следующей программе таким образом, указав:-print0
Теперь перейдем к вашим примерам:
find . -type f -iname "*.cr2" | cp destination_directory
не копирует найденные файлы, так как cp не читает из стандартного ввода. Вам придется использовать:
find . -type f -iname "*.cr2" | xargs cp -t destination_directory
или для обработки путей с пробелами:
find . -type f -iname "*.cr2" -print0 | xargs -0 cp -t destination_directory
Примерно с такой же эффективностью можно было бы сделать:
find . -type f -iname "*.cr2" -exec cp -t destination_directory {} +
(Как указал G-Man, слово {}
должно быть в конце, перед+
») Все вышеперечисленное делаетнетДля этого я создаю иерархию в целевом каталоге и по давней привычке, даже если исходный каталог плоский, вместо этого я использую cpio
:
find . -type f -iname "*.cr2" -print0 | cpio -pdmv0 destination_directory
который наглядно перечисляет, что он делает по ходу дела.
Соответствующие части из man find
:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command
until an argument consisting of `;' is encountered. The string
`{}' is replaced by the current file name being processed
everywhere it occurs in the arguments to the command, not just
in arguments where it is alone, as in some versions of find.
Both of these constructions might need to be escaped (with a
`\') or quoted to protect them from expansion by the shell.
See the EXAMPLES section for examples of the use of the -exec
option. The specified command is run once for each matched
file. The command is executed in the starting directory.
There are unavoidable security problems surrounding use of the
-exec action; you should use the -execdir option instead.
-exec command {} +
This variant of the -exec action runs the specified command on
the selected files, but the command line is built by appending
each selected file name at the end; the total number of invoca‐
tions of the command will be much less than the number of
matched files. The command line is built in much the same way
that xargs builds its command lines. Only one instance of `{}'
is allowed within the command. The command is executed in the
starting directory.