XARGS с несколькими аргументами

У меня есть источник ввода,input.txt

a.txt
b.txt
c.txt

Я хочу передать эти данные в программу следующим образом:

my-program --file=a.txt --file=b.txt --file=c.txt

Поэтому я стараюсь использоватьxargs, но без удачи.

cat input.txt | xargs -i echo "my-program --file"{}

Это дает

my-program --file=a.txt
my-program --file=b.txt
my-program --file=c.txt

Но я хочу

my-program --file=a.txt --file=b.txt --file=c.txt

Любая идея?

Ответы на вопрос(12)

На самом деле, это относительно просто:

... | sed 's/^/--prefix=/g' | xargs echo | xargs -I PARAMS your_cmd PARAMS

sed 's/^/--prefix=/g' необязательно, в случае, если вам нужно добавить к каждому параметру префикс --prefix =.

xargs echo превращает список строк параметров (один параметр в каждой строке) в список параметров в одной строке иxargs -I PARAMS your_cmd PARAMS позволяет запустить команду, размещая параметры там, где вы хотите.

Такcat input.txt | sed 's/^/--file=/g' | xargs echo | xargs -I PARAMS my-program PARAMS делает то, что вам нужно (при условии, что все строки в input.txt просты и квалифицируются как одно значение параметра каждая).

Проще использовать два вызова xargs: 1-й для преобразования каждой строки в--file=...2-й, чтобы сделать вещь xargs ->

$ cat input.txt | xargs [email protected] echo [email protected] | xargs echo my-program
my-program --file=a.txt --file=b.txt --file=c.txt

Ты можешь использоватьsed ставить префикс--file= на каждую линию, а затем позвонитеxargs:

sed -e 's/^/--file=/' input.txt | xargs my-program
 RVT24 нояб. 2014 г., 02:59
После этого (четыре года спустя) Google придумал свое (похожее) решение ... конкретно, для этого вопроса это было бы больше похоже на:echo a.txt b.txt c.txt | xargs | sed 's/ / --file=/g' | xargs echo my-program --file    Моим сложным решением было больше передать имена файлов (такие как журналы Apache) в длинную командную строку. Например:ls /var/log/apache2/*access.log | xargs | sed 's/ / -f /g' | xargs echo myprogram -f

xargs не работает таким образом. Пытаться:

  myprogram $(sed -e 's/^/--file=/' input.txt)

не слушайте их всех :) просто посмотрите на этот пример:

echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2' | xargs

выход будет

this is first:argument1 second:argument2 third:argument3
 holms01 мар. 2018 г., 16:39
@sauliux не работает в Makefile :(
 np2016 янв. 2019 г., 22:59
зачем труба к xargs во второй раз нужна в конце?
 user375138522 апр. 2015 г., 16:56
га. «Не слушай их всех», - смеюсь я.
 Mohsen Abasi15 нояб. 2017 г., 15:15
Но я думаю, что этот ответ неверен. Файл имеет 3 строки, но в этом ответе есть 3 аргумента в 1 строке!
 patrickdavey01 февр. 2016 г., 19:14
Если вы пытаетесь сделать это на OSX, используйте -L1, например.echo argument1 argument2 argument3 | xargs -L1 bash -c 'echo this is first:$0 second:$1 third:$2' | xargs
 Fernando Irarrázaval G26 февр. 2019 г., 21:21
Вы должны использовать двойные знаки $ в make-файле. Пример:echo zero one | xargs -L1 -n 4 sh -c 'echo $$0'

Я искал решение для этой проблемы и пришел к выводу о кодированиисценарий в середине.

чтобы преобразовать стандартный вывод для следующего примера, используйте разделитель -n '\ n'

пример:

 [email protected]:~$ echo "file1.txt file2.txt" | xargs -n1 ScriptInTheMiddle.sh

 inside the ScriptInTheMidle.sh:
 !#/bin/bash
 var1=`echo $1 | cut -d ' ' -f1 `
 var2=`echo $1 | cut -d ' ' -f2 `
 myprogram  "--file1="$var1 "--file2="$var2 

Чтобы это решение работало, вам нужно иметь пробел между этими аргументами file1.txt и file2.txt, или любым другим разделителем, который вы выбираете, и еще одна вещь, внутри скрипта, убедитесь, что вы проверили -f1 и -f2, как они означают «взять первое слово и возьмите второе слово "в зависимости от найденной позиции первого разделителя (разделителями могут быть '' ';' '." все, что вы хотите между одинарными кавычками. Добавьте столько параметров, сколько пожелаете.

Проблема решена с помощью xargs, cut и некоторых сценариев bash.

Ура!

если вы хотите пройти мимо, у меня есть несколько полезных советовhttp://hongouru.blogspot.com

Как насчет:

echo a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c '
   echo my-program --file="$1" --file="$2" --file="$3"
' argv0

Вот решение, использующее sed для трех аргументов, но оно ограничено тем, что применяет одно и то же преобразование к каждому аргументу:

cat input.txt | sed 's/^/--file=/g' | xargs -n3 my-program

Вот метод, который будет работать для двух аргументов, но обеспечивает большую гибкость:

cat input.txt | xargs -n 2 | xargs -I{} sh -c 'V="{}"; my-program -file=${V% *} -file=${V#* }'

Никто еще не упомянул эхо от цикла, поэтому я добавлю это для полноты картины (это будет мой второй подход, первый - sed):

for line in $(< input.txt) ; do echo --file=$line ; done | xargs echo my-program

Это потому чтоecho печатает новую строку. Попробуйте что-то вроде

echo my-program `xargs --arg-file input.txt -i echo -n " --file "{}`
 thiagowfx09 янв. 2014 г., 17:05
Используйте расширение подобласти, какecho my-program $(xargs --arg-file input.txt -i echo -n " --file "{})
 Jonathan Leffler25 сент. 2010 г., 21:05
Что происходит, когда на вход поступает 30 000 имен файлов?

Я наткнулся на похожую проблему и нашел решение, которое мне кажется более приятным и чистым, чем те, что были представлены до сих пор.

Синтаксис дляxargs что я закончил будет (для вашего примера):

xargs -I X echo --file=X

с полной командной строкой:

my-program $(cat input.txt | xargs -I X echo --file=X)

который будет работать как будто

my-program --file=a.txt --file=b.txt --file=c.txt

было сделано (при условииinput.txt содержит данные из вашего примера).

На самом деле, в моем случае мне нужно было сначала найти файлы, а также отсортировать их, поэтому моя командная строка выглядит так:

my-program $(find base/path -name "some*pattern" -print0 | sort -z | xargs -0 -I X echo --files=X)

Немного подробностей, которые могут быть неясными (они были не для меня):

some*pattern необходимо заключить в кавычки, так как в противном случае оболочка расширит его передfind.-print0, затем-z и наконец-0 используйте нулевое разделение, чтобы обеспечить правильную обработку файлов с пробелами или другими проводными именами.

Обратите внимание, что я еще не проверял это глубоко. Хотя, похоже, работает.

Решение Вопроса

Ни одно из приведенных выше решений не работает правильно с именами файлов, содержащими пробел. Некоторые даже терпят неудачу, если имена файлов содержат 'или ". Если ваши входные файлы генерируются пользователями, вы должны быть готовы к неожиданным именам файлов.

GNU Parallel хорошо справляется с этими именами файлов и дает вам (как минимум) 3 различных решения. Если ваша программа принимает 3 и только 3 аргумента, это будет работать:

(echo a1.txt; echo b1.txt; echo c1.txt;
 echo a2.txt; echo b2.txt; echo c2.txt;) |
parallel -N 3 my-program --file={1} --file={2} --file={3}

Или же:

(echo a1.txt; echo b1.txt; echo c1.txt;
 echo a2.txt; echo b2.txt; echo c2.txt;) |
parallel -X -N 3 my-program --file={}

Однако, если ваша программа принимает столько аргументов, сколько поместится в командной строке:

(echo a1.txt; echo b1.txt; echo c1.txt;
 echo d1.txt; echo e1.txt; echo f1.txt;) |
parallel -X my-program --file={}

Посмотрите вступительное видео, чтобы узнать больше:http://www.youtube.com/watch?v=OpaiGYxkSuQ

 Jonathan Leffler25 сент. 2010 г., 21:03
Интересно - не знал про GNU Parallel. Баш - вменяемая оболочка; вам не нужно ставить обратную косую черту после канала, чтобы сказать, что остальная часть команды находится на следующей строке.
 travc13 окт. 2014 г., 18:52
Параллельно с GNU это здорово. Одно предупреждение: в некоторых системах вам нужно параллельно указать опцию --gnu, чтобы она работала разумно. Я никогда больше не использую xargs. Если вы действительно не хотите распараллеливать, вы всегда можете задать опцию «-j 1» (1 задание).
 oklas13 янв. 2017 г., 11:28
Utiliteparallel не всегда доступен, особенно в простом Unix и должен быть установлен, если это возможно. Там интересное решениениже доступны со стандартными инструментами Unix.

Ваш ответ на вопрос