Exec позволяет нам передавать все аргументы одновременно {} +
или передавать их по одному{} \;
Теперь предположим, что я хочу переименовать все в формате JPEG , без проблем это сделать:
find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec mv '{}' '{}'.new \;
Но если мне нужно перенаправить вывод, '{}'
не доступен после перенаправления.
find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec cjpeg -quality 80 '{}' > optimized_'{}' \;
Это не сработает. Я должен был бы использовать цикл for, сохраняя результаты поиска в переменную перед использованием. Допустим, это громоздко.
for f in `find . \( -name '*.jpg' -o -name '*.jpeg' \)`; do cjpeg -quality 80 $f > optimized_$f; done;
Так есть ли лучший способ?
>
пропущенного в третьем примере кода?{}
появляются в более длинных строках, так как такие строки обычно не раскрываются.find
, один раз и применяется к самойfind
команде. В{}
этом контексте не имеет особого значения. Перенаправление не является аргументомfind
и, конечно же, не является частью-exec
предложения.Ответы:
Вы можете использовать
bash -c
вfind -exec
команде и использовать позиционный параметр с командой bash:Этот способ
{}
обеспечен$1
.sh
Перед{}
говорит внутренняя оболочка его «имя», то строка , используемая здесь используется, например , в сообщениях об ошибках. Это обсуждается больше в этом ответе на stackoverflow .источник
У вас есть ответ ( https://unix.stackexchange.com/a/481687/4778 ), но вот почему.
Перенаправление
>
, а также каналы|
и$
расширение выполняются оболочкой до выполнения команды. Поэтому stdout перенаправляется до тогоoptimized_{}
, какfind
будет запущен.источник
Перенаправление должно быть заключено в кавычки, чтобы текущая оболочка не интерпретировала его.
Но его цитирование также позволит избежать перенаправления вывода команды.
Известное решение для этого заключается в вызове оболочки:
В этом случае redirection (
>
) заключена в кавычки в текущей оболочке и работает правильно внутри вызываемой оболочки.called_shell
Используется в качестве$0
параметра (имя) ребенка оболочки (sh
).Это хорошо работает, если к имени файла добавляется суффикс, но не при использовании префикса. Для того чтобы префикс работал, вам нужно удалить и
./
найти префикс перед именами файлов${1#./}
и использовать эту-execdir
опцию.Вы можете (или не может) необходимо использовать
-iname
параметр , чтобы файлы с именем*.JPG
или*.JpG
или другие варианты также включены.И вы можете (или не можете) также вызывать оболочку один раз для каждого каталога, а не один раз для каждого файла, добавив loop (
for f do … ; done
) и a+
в конце:И, наконец, поскольку
cjpeg
есть возможность прямой записи в файл, перенаправления можно избежать как:источник
cjpeg
имеет опцию, которая позволяет вам писать в именованный файл, а не стандартный вывод. Если ваша версияfind
поддерживает этот-execdir
параметр, вы можете воспользоваться этим, чтобы сделать перенаправление ненужным.Примечание: это фактически предполагает версию BSD
find
, которая, по-видимому,./
удаляет начальную букву из имени файла при расширении до{}
. (Или наоборот, GNUfind
добавляет./
к названию. Нет никакого стандарта, чтобы сказать, какое поведение является "правильным".)источник
find
поддерживаете-execdir
, вы можете использовать это вместо-exec
. Это заставляет команду выполняться в каталоге, где файл был найден, и{}
станетaa.jpg
вместо./t2/aa.jpg
.cjpeg: can't open optimized_./aa.jpg
.find
и BSDfind
. (Опасности использования нестандартных расширений.)./
кажется, более склонно к ошибкам. В этом ответе предлагается разумное решение .Создайте скрипт cjq80:
Сделайте это исполняемым
И используйте его в -exec:
источник