wake-up-neo.com

xargs mit mehreren Argumenten

Ich habe eine Quelleingabe, input.txt

a.txt
b.txt
c.txt

Ich möchte diese Eingabe wie folgt in ein Programm einspeisen:

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

Also versuche ich xargs zu verwenden, aber ohne Glück.

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

Es gibt

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

Aber ich möchte 

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

Irgendeine Idee?

43
Howard

Keine der bisher angegebenen Lösungen befasst sich korrekt mit Dateinamen, die Leerzeichen enthalten. Einige schlagen sogar fehl, wenn die Dateinamen 'oder' enthalten. Wenn Ihre Eingabedateien von Benutzern generiert werden, sollten Sie auf überraschende Dateinamen vorbereitet sein.

GNU Parallel verarbeitet diese Dateinamen und gibt (mindestens) 3 unterschiedliche Lösungen an. Wenn Ihr Programm 3 und nur 3 Argumente benötigt, funktioniert dies:

(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}

Oder:

(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={}

Wenn Ihr Programm jedoch so viele Argumente akzeptiert, wie in die Befehlszeile passen:

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

In dem Intro-Video erfahren Sie mehr: http://www.youtube.com/watch?v=OpaiGYxkSuQ

22
Ole Tange

hört euch nicht alle an :) schaut euch dieses Beispiel an:

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

ausgabe wird sein

this is first:argument1 second:argument2 third:argument3
63
sauliux

Wie wäre es mit:

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

Sie können sed verwenden, um --file= in jede Zeile ein Präfix einzugeben und dann xargs aufzurufen:

sed -e 's/^/--file=/' input.txt | xargs my-program
5
Bart Sas

Hier ist eine Lösung, die sed für drei Argumente verwendet, sie ist jedoch insofern eingeschränkt, als sie auf jedes Argument dieselbe Transformation anwendet:

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

Hier ist eine Methode, die für zwei Bereiche geeignet ist, jedoch mehr Flexibilität bietet:

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

Ich bin auf ein ähnliches Problem gestoßen und habe eine Lösung gefunden, die meiner Meinung nach schöner und sauberer ist als die bisher vorgestellten.

Die Syntax für xargs, mit der ich geendet habe, wäre (für Ihr Beispiel):

xargs -I X echo --file=X

mit einer vollständigen Befehlszeile:

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

was funktionieren wird als ob

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

wurde fertig (wenn input.txt Daten aus Ihrem Beispiel enthält).


Eigentlich musste ich in meinem Fall zuerst die Dateien finden und auch sortiert, so dass meine Befehlszeile folgendermaßen aussieht:

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

Einige Details, die möglicherweise nicht klar sind (sie waren nicht für mich):

  • some*pattern muss in Anführungszeichen gesetzt werden, da Shell ihn sonst erweitern würde, bevor er an find übergeben wird.
  • -print0, dann -z und schließlich -0 verwenden die Nulltrennung, um die korrekte Handhabung von Dateien mit Leerzeichen oder anderen verkabelten Namen sicherzustellen.

Beachten Sie jedoch, dass ich es noch nicht gründlich getestet habe. Obwohl es zu funktionieren scheint.

2
Adam Badura

Ich suchte nach einer Lösung für dieses exakte Problem und kam zu dem Schluss, dass ein -Skript in der Mitte codiert wurde.

um die Standardausgabe für das nächste Beispiel zu transformieren, verwenden Sie das Trennzeichen -n '\ n'

beispiel:

 [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 

Damit diese Lösung funktioniert, müssen Sie ein Leerzeichen zwischen den Argumenten file1.txt und file2.txt haben. Wenn Sie sich für ein anderes Trennzeichen entscheiden, stellen Sie sicher, dass Sie innerhalb des Skripts -f1 und -f2 überprüfen, da sie bedeuten erstes Wort und nimm das zweite Wort "abhängig von der gefundenen Position des ersten Begrenzungsmessers (Begrenzungszeichen könnten '' ';' '." sein, was auch immer Sie zwischen einfachen Anführungszeichen wünschen. Fügen Sie so viele Parameter hinzu, wie Sie möchten.

Problem gelöst mit xargs, cut und einigen bash-Skripten.

Prost!

wenn Sie vorbeikommen möchten, habe ich einige nützliche Tipps http://hongouru.blogspot.com

1
HoNgOuRu

Eigentlich ist es relativ einfach:

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

Der sed 's/^/--prefix=/g' ist optional, falls Sie jedem Parameter etwas --prefix = voranstellen müssen.

Der xargs echo verwandelt die Liste der Parameterzeilen (einen Parameter in jeder Zeile) in eine Liste der Parameter in einer einzelnen Zeile. Mit dem Code xargs -I PARAMS your_cmd PARAMS können Sie einen Befehl ausführen und die Parameter an beliebiger Stelle platzieren.

cat input.txt | sed 's/^/--file=/g' | xargs echo | xargs -I PARAMS my-program PARAMS macht also das, was Sie brauchen (vorausgesetzt, alle Zeilen in input.txt sind einfach und gelten jeweils als ein einzelner Parameterwert).

1

Dies liegt daran, dass echo eine neue Zeile druckt. Versuchen Sie etwas wie

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

xargs funktioniert nicht so. Versuchen:

 myprogram $ (sed -es/^/- file =/'input.txt) 
1
Burton Samograd

Es ist einfacher, wenn Sie zwei xargs-Aufrufe verwenden: 1st, um jede Zeile in --file=... zu transformieren

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

Bisher hat noch niemand erwähnt, dass er aus einer Schleife widerhallt. Ich werde dies der Vollständigkeit halber zulassen (es wäre mein zweiter Ansatz, der sed der erste):

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