Я пытаюсь запустить команду расширения оболочки для всех файлов, найденных find
команда. Я пробовал -exec и xargs, но оба потерпели неудачу. Кто-нибудь может объяснить мне, почему? Я на Mac для протокола.
find . -name "*.php" -exec expand -t 4 {} > {} \;
Это просто создает файл {}
со всем выводом вместо перезаписи каждого отдельного найденного файла.
find . -name "*.php" -print0 | xargs -0 -I expand -t 4 {} > {}
И это просто выводит
4 {}
xargs: 4: No such file or directory
find не расширяет все волшебным образом {}
экземпляров после запуска, просто в тех местах, где он их видит, в собственной командной строке. Если вы хотите использовать перенаправление bash в своей команде, вам нужно использовать его в команде оболочки bash следующим образом:
find . -name "*.php" -exec bash -c 'expand -t 4 {} > {}' \;
Как вы это написали, вывод find . -name "*.php" -exec expand -t 4 {}
отправляется в файл {}
.
И во втором примере, который вы привели, команда find печатает список файлов, которые затем передаются в xargs, полностью не связанными с командой find. xargs
работает, выполняя команду один раз для каждого ввода элемента: find /tmp -name core -type f -print0 | xargs -0 /bin/rm -f
- хороший пример того, как его следует использовать. Наконец, последний раздел этого командного конвейера выводит результаты в файл {}
.
Следует понимать, что каждый элемент командного конвейера полностью отделен от всех остальных. Если вы хотите многократно использовать строку в конвейере, вы должны поместить ее в переменную оболочки, чтобы сохранить ее. Например, вы можете использовать цикл bash for следующим образом (дополнительная сложность заключается в правильной обработке файлов с пробелами в их именах, например find -0
делает автоматически):
#!/bin/bash
shopt -s globstar
for f in **; do
if ! echo $f | grep -i -q .php ; then
continue
fi
expand -t 4 $f > ${f}.ex
mv ${f}.ex $f
done
Вам также следует использовать временные файлы, а не редактировать на месте. И вы можете сделать это в два этапа (т. Е. Не выполнять mv
изначально) на случай, если вы ошиблись. Было бы неудачно случайно уничтожить все ваши файлы php.
Наконец, вы можете использовать xargs -I stringtoreplace
вариант. Если вы используете -i
без аргументов это то же самое, что -I {}
, но труднее читать. В этом случае ваш второй метод будет
find . -name "*.php" -print0 | xargs -0 -I [file] expand -t 4 [file] > [file]
Вы можете использовать -iname
вместо того -name
или grep -i
вместо того grep
, если у вас есть .PHP
файлы.
Для чего-то вроде этого я обычно делал:
find . -type f | grep php$ | xargs -i expand -t 4 {} > {}
Это разбивается как:
find . -type f
: Найти все файлы из текущего каталога вниз
| grep php$
: Пропустите результат через grep, чтобы найти все имена файлов, заканчивающиеся на php
| xargs -i expand -t 4 {} > {}
: Для каждого файла вызовите expand -t 4 <file> > <file>
Обратите внимание на использование -i
не -I
для xargs
, а за счет фильтра через grep
нет необходимости в -0
аргумент.
Этот метод немного медленнее для большого количества файлов, но должен работать должным образом.
Вы также можете попробовать:
find . -name "*.php" -print0 | xargs -0 -i expand -t 4 {} > {}
Снова обратите внимание на использование -i
скорее, чем -I
.