Hur analyserar jag varje rad i en textfil som ett argument till ett kommando?

Jag vill skriva ett skript som tar ett .txt filnamn som argument, läser filraden för rad och skickar varje rad till ett kommando. Den kör till exempel command --option "LINE 1", sedan command --option "LINE 2", etc. Utdata från kommandot skrivs till en annan fil. Hur ska jag göra det? Jag vet inte var jag ska börja.

Svar

Använd while read loop:

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

Ett annat är att omdirigera utdata med block:

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

Det sista är att öppna filen:

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 

Om ett av kommandona läser inmatning skulle det vara bra idé att använda en annan fd för inmatning så kommandona kommer inte att äta den (här förutsatt att ksh, zsh eller bash för -u 3, använd <&3 istället bärbart):

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

Fin allierad för att acceptera argument kan du göra:

#!/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" 

Vilken man kan köra som:

bash script.sh file another_file 

Extra idé. Använd bash, använd readarray:

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

Obs: IFS= kan utelämnas om du inte tänker ha linjevärden trimmade av ledande och efterföljande mellanslag.

Svar

Ett annat alternativ är xargs.

Med GNU xargs:

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

{} är platshållaren för textraden.

Annat xargs har vanligtvis inte -a, -d, men vissa har -0 för NUL-avgränsad ingång. Med dessa kan du göra:

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

På Unix-överensstämmande system (-I är valfritt i POSIX och endast krävs för UNIX-överensstämmande system), måste du förbehandla ingången för att citera raderna i det format som förväntas av xargs:

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

Observera dock att vissa xargs -implementeringar har en mycket låg gräns för argumentets maximala storlek (till exempel 255 på Solaris, det lägsta tillåtna enligt Unix-specifikationen).

Kommentarer

  • reducerbara till <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, nej, det skulle behandla citat och ta bort några tomma.

Svar

Att hålla exakt till frågan:

#!/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 

Kommentarer

  • fungerade som charm 🙂
  • +1 älskade det här, tack

Svar

Det bästa svaret jag har und is:

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

EDIT:

… fyra år senare …

efter flera nedröstningar och lite mer erfarenhet skulle jag rekommendera följande nu:

xargs -l COMMAND < file 

Kommentarer

  • Detta anropar kommandot en gång för varje ord i filen. Du bör också citera referenser till skalvariabler (som i do "$cmd" "$i";) såvida du inte har en anledning att inte göra det; om filen innehöll en * som ett ord i sig, skulle din kod köras $cmd *, vilket naturligtvis skulle köra kommandot med en lista över filerna i den aktuella katalogen.
  • @ G-Man, utom i zsh, `cat` skulle redan expandera * (det ociterade $i kan fortfarande utvidga ett jokertecken (en andra omgång) om expansionen av `cat` introducerar några). Hur som helst är den metoden verkligen fel.
  • +1. Detta kommer att fungera bra, om varje rad bara innehåller den ingång som behövs för att kommandot ska användas utan mellanslag.
  • +1, gillade xargs-lösning
  • Detta fungerar! (den senare redigeringen xargs -l COMMAND < file). Tack!

Svar

 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 

UTGÅNG

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

Svar

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

Ta alla rader i en fil och skicka dem som argument till ett enda kommando, dvs

command line1 line2 line3 .... 

Om du behöver --option flagga före varje rad ändra det andra kommandot till:

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

Kommentarer

  • Vad -1 för använder ed … verkligen?
  • Jag ’ inte nedröstade dig, men personen som förmodligen hade följande skäl: (1) Detta gör inte vad frågan ställer efter. Detta åberopar kommandot en gång med allt innehåll i filen på kommandoraden; snarare än en gång per rad .(2) Detta gör ingenting för att hantera tecken som är speciella för skalet (som kan finnas i filen); t.ex. ', ", <, >, ;, etc. (3) Detta skapar en onödig tillfällig fil. (4) Saker som detta görs vanligtvis med ”här dokument”. (5) Dina ed kommandon är klumpiga; de två första kommandona kan reduceras till %s/^/ / och %j.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *