Вызов нескольких команд с помощью команды xargs
cat a.txt | xargs -I % echo %
В приведенном выше примере xargs принимает echo % в качестве аргумента команды. Но в некоторых случаях, мне нужно несколько команд для обработки вместо одного, например:
cat a.txt | xargs -I % {command1; command2; ... }
но xargs не принимает эту форму. Одно из решений, которое я знаю, заключается в том, что я могу определить функцию для обертывания команд, но это не конвейер, я не предпочитаю его. Есть ли другое решение?
10 ответов:
cat a.txt | xargs -I % sh -c 'command1; command2; ...'обратите внимание, что это бесполезное использование кошки. Я бы написал так:
< a.txt xargs -I % sh -c 'command1; command2; ...'(да, перенаправление может быть в начале команды.)
предположительно
command1и/илиcommand2будет содержать один или несколько элементов%символы; в противном случае не было бы смысла к доxargs.
С GNU Parallel вы можете сделать:
cat a.txt | parallel 'command1 {}; command2 {}; ...; 'смотрите вступительные видео, чтобы узнать больше:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
Это просто еще один подход без xargs ни cat:
while read stuff; do command1 "$stuff" command2 "$stuff" ... done < a.txt
одна вещь, которую я делаю, это добавить .bashrc/.профиль этой функции:
function each() { while read line; do for f in "$@"; do $f $line done done }тогда вы можете делать такие вещи, как
... | each command1 command2 "command3 has spaces", который является менее подробной, чем xargs и остается. Вы также можете изменить функцию, чтобы вставить значение из чтения в произвольном месте в командах для каждого, если вам также нужно это поведение.
можно использовать
cat file.txt | xargs -i sh -c 'command {} | command2 {} && command3 {}'{} = переменная для каждой строки в текстовом файле
другое возможное решение, которое работает для меня-это что-то вроде -
cat a.txt | xargs bash -c 'command1 $@; command2 $@' bashобратите внимание на 'bash' в конце - я предполагаю, что он передается как argv[0] в bash. Без него в этом синтаксисе теряется первый параметр к каждой команде. Это может быть любое слово.
пример:
cat a.txt | xargs -n 5 bash -c 'echo -n `date +%Y%m%d-%H%M%S:` ; echo " data: " $@; echo "data again: " $@' bash
Я предпочитаю стиль, который позволяет в режиме сухого хода (без
| sh):cat a.txt | xargs -I % echo "command1; command2; ... " | shработает и с трубами:
cat a.txt | xargs -I % echo "echo % | cat " | sh
немного опоздал на вечеринку.
я использую формат ниже для сжатия моих каталогов с тысячами крошечных файлов перед миграцией. Если вам не нужны одинарные кавычки внутри команд, это должно работать.
С некоторыми изменениями, я уверен, что это будет полезно для кого-то. Проверено в
Cygwin(babun)find . -maxdepth 1 ! -path . -type d -print0 | xargs -0 -I @@ bash -c '{ tar caf "@@.tar.lzop" "@@" && echo Completed compressing directory "@@" ; }'
find .найти здесь-maxdepth 1не заходите в дочерние каталоги! -path .исключить . / Текущий путь к каталогу-type dсовпадают только каталоги-print0отдельный вывод по нулевым байтам \0| xargsтруба в xargs-0входной сигнал null отделенные байты-I @@местозаполнитель @@. Замените @@ на ввод.bash -c '...'выполнить команду Bash
группировка&&выполнить следующую команду только в том случае, если предыдущая команда завершилась успешно (выход 0)финал
;важно, иначе это будет неудача.выход:
Completed compressing directory ./Directory1 with meta characters in it Completed compressing directory ./Directory2 with meta characters in it Completed compressing directory ./Directory3 with meta characters in itОбновление 2018 Июля:
если вы любите хаки и играть вокруг, вот что интересно:
echo "a b c" > a.txt echo "123" >> a.txt echo "###this is a comment" >> a.txt cat a.txt myCommandWithDifferentQuotes=$(cat <<'EOF' echo "command 1: $@"; echo 'will you do the fandango?'; echo "command 2: $@"; echo EOF ) < a.txt xargs -I @@ bash -c "$myCommandWithDifferentQuotes" -- @@выход:
command 1: a b c will you do the fandango? command 2: a b c command 1: 123 will you do the fandango? command 2: 123 command 1: ###this is a comment will you do the fandango? command 2: ###this is a commentобъяснение:
- создайте один сценарий лайнера и сохраните его в переменной
-xargsчитаетa.txtи выполняет его какbashскрипт
-@@убеждается каждый раз вся строка передается
- положить@@после--гарантирует@@принимается в качестве позиционного параметра ввода в , а неbashstartOPTION, т. е. как-cсам по себе, что означаетrun command
--волшебный, он работает со многими другими вещами, т. е.ssh, дажеkubectl
мой текущий BKM для этого
... | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");'к сожалению, это использует perl, который менее вероятно будет установлен, чем bash; но он обрабатывает больше входных данных, чем принятый ответ. (Я приветствую вездесущую версию, которая не полагается на perl.)
@Keiththompson's suggestion of
... | xargs -I % sh -c 'command1; command2; ...'отлично - если у вас нет символа комментария оболочки # в вашем вводе, в этом случае часть первой команды и вся вторая команда будут усеченный.
хэши # могут быть довольно распространенными, если входные данные получены из списка файловой системы, например ls или find, и ваш редактор создает временные файлы с # в их имени.
пример проблемы:
$ bash 1366 $> /bin/ls | cat #Makefile# #README# Makefile READMEОй, вот в чем проблема:
$ bash 1367 $> ls | xargs -n1 -I % sh -i -c 'echo 1 %; echo 2 %' 1 1 1 1 Makefile 2 Makefile 1 README 2 READMEАх, так-то лучше:
$ bash 1368 $> ls | xargs -n1 -I % perl -e 'system("echo 1 %"); system("echo 2 %");' 1 #Makefile# 2 #Makefile# 1 #README# 2 #README# 1 Makefile 2 Makefile 1 README 2 README $ bash 1369 $>
это, кажется, самая безопасная версия.
tr '[\n]' '[]' < a.txt | xargs -r0 /bin/bash -c 'command1 "$@"; command2 "$@";'(
-0может быть удален иtrзаменено перенаправлением (или файл может быть заменен на файл с разделением null вместо этого). Это в основном там, так как я в основном используюxargsСfindС-print0выход) (это также может быть актуальным наxargsверсии без ]' < a.txt | xargs -r0 -n1 /bin/bash -c 'command1 "$@"; command2 "$@";'или с несколько меньшим количеством процессов:
tr '[\n]' '[]' < a.txt | xargs -r0 /bin/bash -c 'for f in "$@"; do command1 "$f"; command2 "$f"; done;'если у вас есть GNU
xargsили другой с-Pрасширение и вы хотите запустить 32 процесса параллельно, каждый с не более чем 10 параметров для каждой команды:tr '[\n]' '[]' < a.txt | xargs -r0 -n10 -P32 /bin/bash -c 'command1 "$@"; command2 "$@";'это должно быть устойчивым к любым специальным символам во входных данных. (Если входные данные разделены нулем.) В
trверсия получит некоторые недопустимые входные данные, если некоторые строки содержат новые строки, но это неизбежно с файлом, разделенным новой строкой.