если команда в find -exec

10

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

find -exec echo `echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi` \;

Я знаю, что это глупая команда, я могу использовать другие вещи, такие как -type fили -type d, но я хочу узнать, почему этот кусок кода не работал так, как я ожидал. Он просто печатает каталог для всех из них. Например, пока вывод find:

.
./dir
./dir/file

вывод моего кода:

. : directory
./dir : directory
./dir/file : directory

И вывод

echo `echo dir/file : ;if [ -f dir/file ]; then echo file; else echo directory;fi`

является

dir/file : file

Я работаю над Ubuntu 14.10и используюfind (GNU findutils) 4.4.2

Esref
источник
1
find -exec bash -c 'echo -n "{} : ";if [ -f "{}" ]; then echo file; else echo directory;fi' \;
Костас
1
Спасибо @Costas, но я знаю, что используя bash или sh, я могу достичь своей первоначальной цели, но теперь я хочу понять, почему, если ведет себя иначе с параметром exec.
Esref
Положите аргументы в кавычки "{}". Почему вы используете echoдважды?
Костас
Я уже попробовал это, и это дает тот же результат. find -exec echo echo "{}" : ;if [ -f "{}" ]; then echo file; else echo directory;fi\;
Esref

Ответы:

13

Во-первых, ваш фрагмент выполняет команду

echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi

потому что он нуждается в своем выводе для оценки подстановки команд. Поскольку нет имени файла {}, это производит вывод

{} :
directory

Затем findвыполняется команда с аргументами -exec, echo, {}, :, directory, так что для каждого файла, он выводит имя файла , а затем пробел и : directory.

Что вы на самом деле хотите сделать, так это выполнить фрагмент оболочки echo {} :; …для каждого найденного файла find. Этот фрагмент должен выполняться оболочкой find, а не запускаемой оболочкой find, поскольку он получает данные из findсвоей командной строки. Поэтому вам нужно дать команду findзапустить оболочку:

find -exec sh -c 'echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi' \;

Это лучше, но все же не правильно. Он будет работать с некоторыми (не всеми) findреализациями, если имена ваших файлов не содержат специальных символов, но, поскольку вы интерполируете имя файла в сценарии оболочки, вы разрешаете именам файлов выполнять произвольные команды оболочки, например, если у вас есть файл, названный $(rm -rf /)тогда, команда rm -rf /будет выполнена. Чтобы передать имена файлов в сценарий, передайте их как отдельные аргументы.

Также первая echoпечатает перевод строки после двоеточия. Используйте echo -n(если ваша оболочка поддерживает это) или printfизбегайте этого.

find -exec sh -c 'printf "%s :" "$0"; if [ -f "$0" ]; then echo file; else echo directory; fi' {} \;

Вы можете использовать -exec … {} +для группировки вызовов оболочки, что быстрее.

find -exec sh -c 'for x; do printf "%s :" "$x"; if [ -f "$x" ]; then echo file; else echo directory; fi; done' _ {} +
Жиль "ТАК - перестань быть злым"
источник
3

Другой способ выполнения if; then; else; fiвместе с find:

find |
while read p; do if [ -f "$p" ]; then echo file; else echo directory; fi; done
ncomputers
источник
1
Классное решение. Это позволяет избежать сложных шаблонов кавычек и осложнений подоболочки. Возможно, вы ранее определили функцию оболочки и выполняете ее для файлов, соответствующих условию «если».
Герлос