XARGS с несколькими аргументами - PullRequest
50 голосов
/ 22 сентября 2010

У меня есть источник ввода, 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 ]

76 голосов
/ 02 сентября 2014

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

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
24 голосов
/ 25 сентября 2010

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

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

17 голосов
/ 22 сентября 2010

Как насчет:

echo $'a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c '
   echo my-program --file="$1" --file="$2" --file="$3"
' argv0
6 голосов
/ 22 сентября 2010

Вы можете использовать sed для префикса --file= к каждой строке, а затем вызвать xargs:

sed -e 's/^/--file=/' input.txt | xargs my-program
5 голосов
/ 31 июля 2013

Вот решение, использующее 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#* }'
2 голосов
/ 21 апреля 2018

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

$ cat input.txt | xargs -I@ echo --file=@ | xargs echo my-program
my-program --file=a.txt --file=b.txt --file=c.txt
2 голосов
/ 01 февраля 2016

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

Синтаксис для 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 должно быть заключено в кавычки, так как в противном случае shell расширит его до перехода к find.
  • -print0, затем -z и, наконец, -0 используют нулевое разделение для обеспечения правильной обработки файлов с пробелами или другими проводными именами.

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

1 голос
/ 02 февраля 2012

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

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

пример:

 user@mybox:~$ 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

1 голос
/ 22 сентября 2010

xargs не работает таким образом. Попробуйте:

  myprogram $(sed -e 's/^/--file=/' input.txt)
1 голос
/ 22 сентября 2010

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

echo my-program `xargs --arg-file input.txt -i echo -n " --file "{}`
...