Назад | Перейти на главную страницу

Запуск развертки по набору файлов

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