Hoe ontleed ik elke regel van een tekstbestand als een argument voor een commando?

Ik “ben op zoek naar een script dat een .txt bestandsnaam als argument moet nemen, leest de bestandsregel by line, en geeft elke regel door aan een commando. Het voert bijvoorbeeld command --option "LINE 1" uit, vervolgens command --option "LINE 2", enz. De uitvoer van het commando wordt naar een ander bestand geschreven. Hoe pak ik dat aan? Ik weet niet waar ik moet beginnen.

Antwoord

Gebruik while read loop:

: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file 

Een andere is om de uitvoer per blok om te leiden:

while IFS= read -r LINE; do command --option "$LINE" done < file > another_file 

De laatste is om het bestand te openen:

exec 4> another_file while IFS= read -r LINE; do command --option "$LINE" >&4 echo xyz ## Another optional command that sends output to stdout. done < file 

Als een van de commandos invoer leest, zou het een goede idee om een andere fd te gebruiken voor invoer, zodat de commandos het niet opeten (in de veronderstelling dat ksh, zsh of bash voor -u 3, gebruik <&3 in plaats daarvan draagbaar):

while IFS= read -ru 3 LINE; do ... done 3< file 

Fin bondgenoot om argumenten te accepteren, kunt u het volgende doen:

#!/bin/bash FILE=$1 ANOTHER_FILE=$2 exec 4> "$ANOTHER_FILE" while IFS= read -ru 3 LINE; do command --option "$LINE" >&4 done 3< "$FILE" 

Welke kan worden uitgevoerd als:

bash script.sh file another_file 

Extra idee. Gebruik met bash readarray:

readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done 

Opmerking: IFS= kan worden weggelaten als u het niet erg vindt dat regelwaarden worden bijgesneden van voorloop- en volgspaties.

Antwoord

Een andere optie is xargs.

Met GNU xargs:

xargs -a file -I{} -d"\n" command --option {} other args 

{} is de plaatshouder voor de regel tekst.

Overig xargs hebben over het algemeen geen -a, -d, maar sommige hebben -0 voor NUL-gescheiden invoer. Hiermee kunt u het volgende doen:

< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args 

Op Unix-conforme systemen (-I is optioneel in POSIX en alleen vereist voor UNIX-conforme systemen), “zou je de invoer moeten voorverwerken tot quote de regels in het formaat dat wordt verwacht door xargs:

< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args 

Merk echter op dat sommige xargs implementaties een zeer lage limiet hebben voor de maximale grootte van het argument (255 op Solaris bijvoorbeeld, het minimum toegestaan door de Unix-specificatie).

Reacties

  • reduceerbaar tot <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, nee, dat zou aanhalingstekens verwerken en enkele spaties verwijderen.

Antwoord

Precies houden op de vraag:

#!/bin/bash # xargs -n param sets how many lines from the input to send to the command # Call command once per line [[ -f $1 ]] && cat $1 | xargs -n1 command --option # Call command with 2 lines as args, such as an openvpn password file # [[ -f $1 ]] && cat $1 | xargs -n2 command --option # Call command with all lines as args # [[ -f $1 ]] && cat $1 | xargs command --option 

Reacties

  • werkte prima 🙂
  • +1 vond dit geweldig, bedankt

Antwoord

Het beste antwoord dat ik voor und is:

for i in `cat`; do "$cmd" "$i"; done < $file 

EDIT:

… vier jaar later …

na verschillende stemmen en wat meer ervaring zou ik “nu het volgende aanbevelen:

xargs -l COMMAND < file 

Reacties

  • Dit zal het commando één keer aanroepen voor elk woord in het bestand. Je moet ook altijd verwijzingen naar shell-variabelen citeren (zoals in do "$cmd" "$i";), tenzij je een reden hebt om dat niet te doen; als het bestand een * als een woord op zich zou bevatten, zou uw code $cmd * uitvoeren, waarmee de opdracht natuurlijk zou worden uitgevoerd met een lijst van de bestanden in de huidige directory.
  • @ G-Man, behalve in zsh, de `cat` zou de * al uitbreiden (de niet-geciteerde $i zou nog steeds een jokerteken kunnen uitbreiden (een tweede ronde) als de uitbreiding van `cat` introduceert enkele). In elk geval is die benadering inderdaad verkeerd.
  • +1. Dit werkt prima, als elke regel alleen de invoer bevat die nodig is voor het commando dat zonder spaties wordt gebruikt.
  • +1, vond xargs-oplossing leuk
  • Dit werkt! (de latere bewerking xargs -l COMMAND < file). Bedankt!

Antwoord

 sed "s/"/"\\\\""/g;s/.*/\$* "&"/" <<\FILE |\ sh -s -- command echo --option all of the{&}se li$n\es "are safely shell quoted and handed to command as its last argument following --option, and, here, before that echo FILE 

OUTPUT

--option all of the{&}se li$n\es "are safely shell --option quoted and handed to command as its last argument --option following --option, and, here, before that echo 

Antwoord

ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt 

Neem alle regels van een bestand en geef ze als argumenten door aan een enkel commando, dwz

command line1 line2 line3 .... 

Als je de --option vlag om aan elke regel vooraf te gaan, verander het tweede commando in:

%g/^/s// --option / 

Reacties

  • Wat -1 voor gebruik ik ed … echt?
  • Ik heb je ‘ niet naar beneden gestemd, maar de persoon die dat wel deed, had waarschijnlijk de volgende redenen: (1) Dit doet niet wat de vraag vraagt. Dit roept het commando eenmaal op met alle inhoud van het bestand op de commandoregel; in plaats van eenmaal per regel .(2) Dit doet niets om tekens te behandelen die speciaal zijn voor de shell (die mogelijk in het bestand staan); bijv. ', ", <, >, ;, etc. (3) Dit creëert een onnodig tijdelijk bestand. (4) Dit soort dingen wordt over het algemeen gedaan met “hier documenten”. (5) Uw ed opdrachten zijn onhandig; de eerste twee commandos kunnen worden teruggebracht tot %s/^/ / en %j.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *