Запуск расширения набора файлов
Я пытаюсь запустить команду расширения оболочки для всех файлов, найденных 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
2 ответа
Найти не может волшебным образом расширить все {}
экземпляры после его запуска, просто места, которые он видит их в своей командной строке. Если вы хотите использовать перенаправление 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 следующим образом (дополнительная сложность заключается в правильной обработке файлов с пробелами в их именах, например 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
,