Как выполнить несколько команд при использовании find?


57

Я пытаюсь выполнить несколько команд для вещей, которые я нашел, как я могу добиться этого?

find . -exec cmd1; cmd2

не похоже на работу; вместо этого он запускает cmd2 после того, как cmd1 был выполнен для каждого файла.

Ответы:


40

В этой демонстрации я буду использовать sh -c 'echo first; false'(или true) для первого -exec. Это даст некоторый вывод, а также будет иметь эффект выбранного кода выхода. Затем echo secondбудет использован для второго. Предположим, что в текущем каталоге есть один файл.

$ find . -type f -exec sh -c 'echo first; false' \; -exec echo second \;
first
$ find . -type f -exec sh -c 'echo first; true' \; -exec echo second \;
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second
$ find . -type f \( -exec sh -c 'echo first; false' \; -false -o -exec echo second \; \)
first
second

Настоящая команда такого типа будет выглядеть так:

find . -type f \( -exec command1 \; -false -o -exec command2 \; \)

Во втором наборе экранированные скобки объединяют два -execпредложения. -falseМежду ними заставляет тест состояние на «ложь» , и -oприводит к следующему выражению (второй -exec) , чтобы оценить из-за -false.

От man find:

expr1 expr2
Два выражения в строке берутся с подразумеваемыми "и"; expr2 не оценивается, если expr1 имеет значение false.

expr1 -a expr2
То же, что expr1 expr2.

expr1 -o expr2
или; expr2 не оценивается, если expr1 имеет значение true.


Ах да, я забыл о -o.
Игнасио Васкес-Абрамс

32

Если вам не важно, что cmd1 может предотвратить запуск cmd2 из-за кода ошибки 0:

find . -exec cmd1 \; -exec cmd2 \;

Единственный надежный способ заставить обе команды всегда запускаться, это findвызвать оболочку, которая впоследствии будет запускать команды в последовательности:

find . -exec bash -c 'cmd1; cmd2' filedumper {} \;

2

Если вы не против создать скрипт, который выполняет cmd1 и cmd2, то это просто так:

find . -exec myscript {} \;

или же

find . -exec myscript {} +

Использовать \; или + в зависимости от того, может ли myscript обрабатывать более одного файла за раз (становится проблематично, если в именах файлов есть пробелы и т. д.).

По моему опыту, включение того, что вы делали в сценарий, почти всегда стоило того. Если вам придется сделать это один раз, вам придется сделать это снова.

Но ловкий трюк, чтобы поместить находку внутри сценария:

if [ $# -gt 0 ]; then
    for each; do
        touch $each
    done
else
    find . -exec $0 {} +
fi

Затем myscript работает с любыми файлами, которые вы предоставляете в качестве аргументов для работы, но если вы не предоставите ему никаких аргументов, он запускает find из текущего каталога и затем вызывает себя для найденных файлов. Это обходит тот факт, что find -exec не может вызывать функции оболочки, которые вы определили в своем скрипте.


0

Я пробовал оба предыдущих решения без особой удачи. Этот работал хорошо для меня:

$ for i in `find . -exec echo {} \;`; do cmd1 $i; cmd2 $i; done

Это не будет работать, если список файлов слишком велик.
Алекс

-3

попробуйте команду:

sudo find -name "*[!0-9][1-9].txt" -exec chmod 744 * {} \; -a -exec ls -l {} \; | sort | parallel ls -l

4
Эх, это не очень хорошая идея. *В -execчасти будет расширяться на все файлы в текущем каталоге. Особенно когда работает как sudo.
Slhck
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.