Hvordan analysere hver linje i en tekstfil som et argument til en kommando?

Jeg ønsker å skrive et skript som tar et .txt filnavn som argument, leser fillinjen etter linje, og sender hver linje til en kommando. For eksempel kjører den command --option "LINE 1", deretter command --option "LINE 2" osv. Utdataene fra kommandoen er skrevet til en annen fil. Hvordan kan jeg gjøre det? Jeg vet ikke hvor jeg skal begynne.

Svar

Bruk while read loop:

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

En annen er å omdirigere utdata etter blokk:

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

Sist er å åpne 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 

Hvis en av kommandoene leser inndata, ville det være bra ide om å bruke en annen fd til inndata, så kommandoene ikke spiser den (her forutsatt at ksh, zsh eller bash for -u 3, bruk <&3 i stedet bærbart):

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

Fin alliert for å godta argumenter, kan du gjøre:

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

Hvilken kan kjøre som:

bash script.sh file another_file 

Ekstra idé. Med bash, bruk readarray:

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

Merk: IFS= kan utelates hvis du ikke har noe imot at linjeverdier er trimmet av ledende og etterfølgende mellomrom.

Svar

Et annet alternativ er xargs.

Med GNU xargs:

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

{} er plassholderen for tekstlinjen.

Annet xargs har vanligvis ikke -a, -d, men noen har -0 for NUL-avgrenset inngang. Med disse kan du gjøre:

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

På Unix-samsvarende systemer (-I er valgfritt i POSIX og bare kreves for UNIX-samsvarende systemer), må du forhåndsbehandle inngangen for å sitere linjene i det formatet som forventes av xargs:

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

Vær imidlertid oppmerksom på at noen xargs implementeringer har en veldig lav grense for den maksimale størrelsen på argumentet (for eksempel 255 på Solaris, minimum tillatt av Unix-spesifikasjonen).

Kommentarer

  • reduseres til <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, nei, det vil behandle anførselstegn og fjerne noen blanke.

Svar

Holder presis til spørsmålet:

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

  • fungerte som sjarm 🙂
  • +1 elsket dette, takk

Svar

Det beste svaret jeg und is:

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

EDIT:

… fire år senere …

etter flere nedstemmer og litt mer erfaring, vil jeg anbefale følgende nå:

xargs -l COMMAND < file 

Kommentarer

  • Dette påkaller kommandoen en gang for hvert ord i filen. Du bør også sitere referanser til skallvariabler (som i do "$cmd" "$i";) med mindre du har en grunn til ikke å; hvis filen inneholdt et * som et ord alene, ville koden din kjøre $cmd *, som selvfølgelig ville kjøre kommandoen med en liste over filene i gjeldende katalog.
  • @ G-Man, unntatt i zsh, `cat` ville allerede utvide * (det ikke siterte $i kan fortsatt utvide noe jokertegn (en andre runde) hvis utvidelsen av `cat` introduserer noen). Uansett er den tilnærmingen faktisk feil.
  • +1. Dette fungerer bra, hvis hver linje bare inneholder inngangene som trengs for at kommandoen skal brukes uten mellomrom.
  • +1, likte xargs-løsning
  • Dette fungerer! (den senere redigeringen xargs -l COMMAND < file). Takk!

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 

UTGANG

--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 alle linjer i en fil og sende dem som argumenter til en enkelt kommando, dvs.

command line1 line2 line3 .... 

Hvis du trenger --option flagg for å gå foran hver linje, endre den andre kommandoen til:

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

Kommentarer

  • Hva -1 for bruker ed … virkelig?
  • Jeg ‘ t nedstemte deg, men personen som sannsynligvis hadde følgende grunner: (1) Dette gjør ikke hva spørsmålet ber om. Dette påkaller kommandoen en gang med alt innholdet i filen på kommandolinjen; i stedet for en gang per linje .(2) Dette gjør ingenting for å håndtere tegn som er spesielle for skallet (som kan være i filen); f.eks. ', ", <, >, ;, etc. (3) Dette skaper en unødvendig midlertidig fil. (4) Ting som dette gjøres vanligvis med «her dokumenter». (5) ed kommandoene dine er klønete; de to første kommandoene kan reduseres til %s/^/ / og %j.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *