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

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

Другие вопросы по тегам