xargs met meerdere argumenten

Ik heb een broninvoer, input.txt

a.txt
b.txt
c.txt

Ik wil deze invoer als volgt in een programma invoeren:

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

Dus ik probeer xargste gebruiken, maar zonder geluk.

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

Het geeft

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

Maar ik wil

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

Enig idee?


Antwoord 1, autoriteit 100%

Luister niet naar allemaal. 🙂 Kijk maar naar dit voorbeeld:

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

Uitvoer zal zijn:

this is first:argument1 second:argument2 third:argument3

Antwoord 2, autoriteit 26%

Geen van de tot nu toe gegeven oplossingen gaat correct om met bestandsnamen die ruimte bevatten. Sommige mislukken zelfs als de bestandsnamen ‘ of ” bevatten. Als uw invoerbestanden worden gegenereerd door gebruikers, moet u voorbereid zijn op verrassende bestandsnamen.

GNU Parallelgaat goed om met deze bestandsnamen en geeft je (minstens) 3 verschillende oplossingen. Als je programma 3 en slechts 3 argumenten nodig heeft, dan werkt dit:

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

Of:

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

Als uw programma echter zoveel argumenten nodig heeft als op de opdrachtregel passen:

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

Bekijk de introductievideo voor meer informatie: http://www.youtube.com/watch? v=OpaiGYxkSuQ


Antwoord 3, autoriteit 15%

Wat dacht je van:

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

Antwoord 4, autoriteit 6%

Het is eenvoudiger als u twee xargs-aanroepen gebruikt: ten eerste om elke regel te transformeren in --file=..., ten tweede om het xargs-ding daadwerkelijk te doen ->

$ cat input.txt | xargs -I@ echo --file=@ | xargs echo my-program
my-program --file=a.txt --file=b.txt --file=c.txt

Antwoord 5, autoriteit 5%

U kunt sedgebruiken om --file=voor elke regel te plaatsen en vervolgens xargs:

aanroepen

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

Antwoord 6, autoriteit 3%

Hier is een oplossing die sed gebruikt voor drie argumenten, maar deze is beperkt omdat het dezelfde transformatie toepast op elk argument:

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

Hier is een methode die voor twee argumenten werkt, maar meer flexibiliteit biedt:

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

Antwoord 7, autoriteit 2%

Ik stuitte op een soortgelijk probleem en vond een oplossing die volgens mij mooier en schoner is dan de oplossingen die tot nu toe zijn gepresenteerd.

De syntaxis voor xargswaarmee ik ben geëindigd, zou zijn (voor jouw voorbeeld):

xargs -I X echo --file=X

met als volledige opdrachtregel:

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

die zal werken alsof

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

is gedaan (op voorwaarde dat input.txtgegevens uit uw voorbeeld bevat).


Eigenlijk moest ik in mijn geval eerst de bestanden vinden en ze ook gesorteerd, zodat mijn opdrachtregel er als volgt uitziet:

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

Enkele details die misschien niet duidelijk zijn (ze waren niet voor mij):

  • some*patternmoet tussen aanhalingstekens staan, omdat shell het anders zou uitbreiden voordat het doorgaat naar find.
  • -print0, dan -zen tot slot -0gebruiken null-scheiding om een ​​correcte verwerking van bestanden met spaties of andere bekabelde namen te garanderen .

Houd er echter rekening mee dat ik het nog niet grondig heb getest. Hoewel het lijkt te werken.


Antwoord 8

xargs werkt niet op die manier. Probeer:

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

Antwoord 9

Het is omdat echoeen nieuwe regel afdrukt. Probeer iets als

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

Antwoord 10

Ik was op zoek naar een oplossing voor dit exacte probleem en kwam tot de conclusie om een ​​script in het middente coderen.

gebruik het scheidingsteken -n ‘\n’ om de standaarduitvoer voor het volgende voorbeeld te transformeren

voorbeeld:

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 

Om deze oplossing te laten werken, moet u een spatie hebben tussen die argumenten file1.txt en file2.txt, of welk delimeter u ook kiest, nog een ding, zorg ervoor dat u in het script -f1 en -f2 aanvinkt zoals ze betekenen “neem het eerste woord en neem het tweede woord” afhankelijk van de positie van het eerste delimeter gevonden (scheidingstekens kunnen ‘ ‘ ‘;’ ‘.’ wat je maar wilt tussen enkele aanhalingstekens .
Voeg zoveel parameters toe als u wilt.

Probleem opgelost met xargs, cut en wat bash-scripting.

Proost!

Als je langs wilt komen, heb ik een paar handige tips http://hongouru.blogspot.com


Antwoord 11

Eigenlijk is het relatief eenvoudig:

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

De sed 's/^/--prefix=/g'is optioneel, voor het geval je elke param moet voorvoegen met een –prefix=.

De xargs echoverandert de lijst met paramregels (één param in elke regel) in een lijst met params in een enkele regel en de xargs -I PARAMS your_cmd PARAMSstelt je in staat een commando uit te voeren, waarbij je de parameters plaatst waar je maar wilt.

Dus cat input.txt | sed 's/^/--file=/g' | xargs echo | xargs -I PARAMS my-program PARAMSdoet wat je nodig hebt (ervan uitgaande dat alle regels binnen input.txt eenvoudig zijn en elk als een enkele parameterwaarde kwalificeren).


Antwoord 12

Er is nog een leuke manier om dit te doen, als je het aantal bestanden niet vooraf weet:

my-program $(find . -name '*.txt' -printf "--file=%p ")

Antwoord 13

Niemand heeft nog gesproken over echo’s uit een lus, dus ik zal dat voor de volledigheid toevoegen (het zou mijn tweede benadering zijn, waarbij de sed de eerste is):

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

Other episodes