Как передать вывод команды в виде нескольких аргументов другой команде

Я хочу передать каждый вывод из команды в виде нескольких аргументов во вторую команду, например:

grep "pattern" input

возвращает:

file1
file2
file3

и я хочу скопировать эти выходы, например:

cp file1  file1.bac
cp file2  file2.bac
cp file3  file3.bac

Как я могу это сделать за один раз? Что-то вроде:

grep "pattern" input | cp $1  $1.bac

Ответы

Ответ 1

Вы можете использовать xargs:

grep 'pattern' input | xargs -I% cp "%" "%.bac"

Ответ 2

Вы можете использовать $() для интерполяции вывода команды. Таким образом, вы можете использовать kill -9 $(grep -hP '^\d+$' $(ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }')), если хотите.

Ответ 3

В дополнение к Хорошему ответу Криса Джет-Янга, я бы сказал, что xargs также является хорошим решением для этих ситуаций:

grep ... `ls -lad ... | awk '{ print $9 }'` | xargs kill -9

сделает это. Все вместе:

grep -hP '^\d+$' `ls -lad /dir/*/pid | grep -P '/dir/\d+/pid' | awk '{ print $9 }'` | xargs kill -9

Ответ 4

Для полноты я также упомянул подстановку команд и объясню, почему это не рекомендуется:

  cp $(grep -l "pattern"  ) каталог/
Код>

(Синтаксис backtick cp `grep -l "pattern" input` directory/ примерно эквивалентен, но он устарел и громоздкий, не используйте его.)

Это не удастся, если вывод из grep создает имя файла, содержащее пробел или метасимвол оболочки.

Конечно, это хорошо, если вы точно знаете, какие имена файлов grep могут произвести, и проверили, что ни одна из них не является проблематичной. Но для сценария производства не используйте это.

В любом случае, для сценария OP, где вам нужно отдельно относиться к каждому соответствию и добавлять к нему расширение, альтернативы xargs или при чтении в любом случае превосходны.

В худшем случае (имея в виду проблемные или неуказанные имена файлов) передайте совпадения в подоболочку через xargs:

  grep -l "pattern" input |
xargs -r sh -c 'для f; do cp "$ f" "$ f.bac"; сделанный' _
Код>

... где очевидно, что script внутри цикла для может быть сколь угодно сложным.

В идеальном случае команда, которую вы хотите запустить, проста (или универсальна) достаточно, чтобы вы могли просто передать ей произвольно длинный список имен файлов. Например, GNU cp имеет параметр -t, чтобы облегчить это использование xargs (опция -t вам следует поместить в командной строке целевой каталог first, поэтому вы можете поместить столько файлов, сколько хотите в конце команды):

  grep -l "pattern" input | xargs cp -t destdir
Код>

который будет расширяться в

  cp -t destdir file1 file2 file3 file4...
Код>

для количества совпадений, таких как xargs, может вписываться в командную строку cp, повторяется столько раз, сколько требуется, чтобы передать все файлы в cpкод > . (К сожалению, это не соответствует сценарию OP, если вам нужно переименовать каждый файл во время копирования, вам нужно передать всего два аргумента за вызов cp: имя исходного файла и имя целевого файла чтобы скопировать его.)

Иными словами, если вы используете синтаксис подстановки команд и grep создает длинный список совпадений really, вы рискуете столкнуться с ARG_MAX и слишком длинный список "Аргумент списка"; но xargs будет специально избегать этого, вместо этого копируя только столько аргументов, сколько он может безопасно перейти к cp за раз и запустить cp несколько раз при необходимости.