Запуск расширения набора файлов
Я пытаюсь запустить команду расширения оболочки для всех файлов, найденных 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,