Почему я не могу найти результаты в cp, но он работает с помощью exec? - PullRequest
0 голосов
/ 09 ноября 2018

Я использую find для просмотра файлов в нескольких каталогах с определенным расширением. Я пытался

find /path/to/encompassing/directory/ -d -name "*modified.tif" | xargs  cp Destination_Directory/ 

но это не сработало. Использование

find /path/ -d -name "*modified.tif" -type f -exec cp {} Destination_Directory \;

работает, но я не понимаю, почему xargs не работает.

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Если вы напишите

find -name '*modified.tif' | xargs cp directory

тогда это то же самое, что писать

cp directory filename file1modified.tif file2modified.tif

(или какие-либо имена файлов совпадают), что неверно, потому что xargs по умолчанию добавляет аргументы.

find -name '*modified.tif' -exec cp {} directory \;

совпадает с

cp file1modified.tif directory
cp file2modified.tif directory

что вы хотите.

Вы можете достичь того же с xargs, используя

xargs -I{} cp {} directory

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

Чтобы не вызывать cp один раз для файла, вы можете использовать опцию -t для cp, чтобы копируемые файлы можно было добавить в конец команды (требуется GNU cp):

find -name '*modified.tif' | xargs cp -t directory

, что эквивалентно

cp -t directory file1modified.tif file2modified.tif

или лучше, заботясь о пробелах в именах файлов,

find -name '*modified.tif' -print0 | xargs -0 cp -t directory

В качестве альтернативы, без xargs:

find -name '*modified.tif' -exec cp -t directory {} +

, где -exec {} + обязательно вызывает cp как можно меньше раз.

0 голосов
/ 09 ноября 2018

xargs передает каждое слово из стандартного ввода в качестве аргумента last в cp, а не в первое. В результате вы пытаетесь запустить серию команд

cp Destination_Directory/ foo
cp Destination_Directory/ bar
# etc

Если вы используете GNU cp, вы можете исправить это, просто используя опцию -t, чтобы указать, что Destination_Directory является целью , а не источником.

... | xargs cp -t Destination_Directory
# cp -t Destination_Directory foo
# cp -t Destination_Directory bar
# etc

Вы можете иметь возможность использовать опцию -I в xargs, чтобы она использовала имя входящего файла в качестве первого аргумента:

... | xargs -I '{}' cp '{}' Destination_Directory

однако, это делает много предположений относительно имен, которые find будет выдавать. (Никаких начальных или конечных пробелов и новых строк в именах файлов.) (В этом отношении xargs без -I обрабатывает каждое разделенное пробелами слово из его ввода в качестве отдельного аргумента для вызова cp.) В общем, вы не должны пытаться использовать вывод find программно. Вместо этого используйте -exec основной.

Ваш код

find /path/ -d -name "*modified.tif" -type f -exec cp {} Destination_Directory \;

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

0 голосов
/ 09 ноября 2018

Я не использую xargs, но думаю, что это должно работать так:

cp `find  /path/to/encompassing/directory/ -d  -name "*modified.tif"` Destination_Directory/

Тогда не нужно трубы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...