Cum se analizează fiecare linie a unui fișier text ca argument pentru o comandă?

Caut să scriu un script care să ia un nume de fișier .txt ca argument, citește linia de fișier după linie și trece fiecare linie la o comandă. De exemplu, rulează command --option "LINE 1", apoi command --option "LINE 2" etc. Rezultatul comenzii este scris într-un alt fișier. Cum mă descurc? Nu știu de unde să încep.

Răspuns

Utilizați bucla while read:

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

Altul este să redirecționați ieșirea prin bloc:

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

Ultima este deschiderea fișierului:

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 

Dacă una dintre comenzi citește intrarea, ar fi bine ideea de a utiliza un alt fd pentru intrare, astfel încât comenzile să nu fie consumate (presupunând ksh, zsh sau bash pentru -u 3, utilizați <&3 în loc portabil):

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

Fin aliat pentru a accepta argumente, puteți face:

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

Care ar putea rula ca:

bash script.sh file another_file 

Idee suplimentară. Cu bash, utilizați readarray:

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

Notă: IFS= poate fi omis dacă nu vă deranjează să aveți valori de linie tăiate de spații de conducere și de spate.

Răspuns

O altă opțiune este xargs.

Cu GNU xargs:

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

{} este titularul locului pentru linia de text.

Altele xargs, în general, nu au -a, -d, dar unele au -0 pentru intrare delimitată de NUL. Cu acestea, puteți face:

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

Pe sistemele conforme Unix (-I este opțional în POSIX și numai necesar pentru sistemele conforme UNIX), ar trebui să pre-procesați intrarea pentru a cita liniile în formatul așteptat de xargs:

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

Cu toate acestea, rețineți că unele implementări xargs au o limită foarte mică pentru dimensiunea maximă a argumentului (255 pe Solaris, de exemplu, minimul permis de specificația Unix).

Comentarii

  • reductibil la <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, nu, care ar procesa ghilimele și ar elimina unele spații goale.

Răspuns

Păstrarea precisă la întrebarea:

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

Comentarii

  • a funcționat ca un farmec 🙂
  • +1 mi-a plăcut acest lucru, mulțumesc

Răspuns

Cel mai bun răspuns und is:

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

EDIT:

… patru ani mai târziu …

după mai multe voturi împotrivă și ceva mai multă experiență aș recomanda acum următoarele:

xargs -l COMMAND < file 

Comentarii

  • Aceasta va invoca comanda o dată pentru fiecare cuvânt din fișier. De asemenea, ar trebui să citați întotdeauna referințe la variabilele shell (ca în do "$cmd" "$i";), cu excepția cazului în care aveți un motiv să nu faceți acest lucru; dacă fișierul conține un * ca un cuvânt singur, codul dvs. ar rula $cmd *, care, desigur, ar rula comanda cu o listă a fișierelor din directorul curent.
  • @ G-Man, cu excepția zsh, `cat` ar extinde deja * ($i necotat ar putea totuși extinde unele metacaractere (a doua rundă) dacă extinderea `cat` introduce câteva). În orice caz, această abordare este într-adevăr greșită.
  • +1. Acest lucru va funcționa bine, dacă fiecare linie conține doar intrarea necesară pentru ca comanda să fie utilizată fără spații.
  • +1, soluție xargs apreciată
  • Aceasta funcționează! (versiunea ulterioară xargs -l COMMAND < file). Mulțumesc!

Răspuns

 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 

IEȘIRE

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

Răspuns

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

Ia toate liniile unui fișier și treceți-le ca argumente la o singură comandă, adică

command line1 line2 line3 .... 

Dacă aveți nevoie de --option semnalizator pentru a precede fiecare linie schimba a doua comandă la:

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

Comentarii

  • Ce -1 pentru folosind ed … într-adevăr?
  • Nu ‘ nu v-am votat în jos, dar persoana care a făcut-o probabil a avut aceste motive: (1) ce cere întrebarea. Aceasta invocă comanda o dată cu tot conținutul fișierului pe linia de comandă; mai degrabă decât o dată pe linie .(2) Acest lucru nu face nimic pentru a gestiona caractere speciale pentru shell (care ar putea fi în fișier); ex., ', ", <, >, ; etc. (3) Acest lucru creează un fișier temporar inutil. (4) Lucruri de genul acesta se fac în general cu „aici documente”. (5) Comenzile ed sunt stângace; primele două comenzi pot fi reduse la %s/^/ / și %j.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *