Jeg ønsker at skrive et script, der tager et .txt filnavn som argument, læser fillinjen efter linje og sender hver linje til en kommando. For eksempel kører den command --option "LINE 1", derefter command --option "LINE 2" osv. Udgangen af kommandoen er skrevet til en anden fil. Hvordan skal jeg gøre det? Jeg ved ikke, hvor jeg skal starte.
Svar
Brug while read loop:
: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file
En anden er at omdirigere output ved blok:
while IFS= read -r LINE; do command --option "$LINE" done < file > another_file
Sidste er at åbne 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 af kommandoerne læser input, ville det være en god idé om at bruge en anden fd til input, så kommandoerne ikke spiser det (her forudsat ksh, zsh eller bash til -u 3, brug <&3 i stedet bærbart):
while IFS= read -ru 3 LINE; do ... done 3< file
Fin allieret for at acceptere argumenter, kan du gø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 man kan køre som:
bash script.sh file another_file
Ekstra idé. Brug bash, brug readarray:
readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done
Bemærk: IFS= kan udelades, hvis du ikke har noget imod at have linjeværdier trimmet af mellemrum i forkant og bagud.
Svar
En anden mulighed er xargs.
Med GNU xargs:
xargs -a file -I{} -d"\n" command --option {} other args
{} er pladsholderen for tekstlinjen.
Andet xargs har generelt ikke -a, -d, men nogle har -0 til NUL-afgrænset input. Med disse kan du gøre:
< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args
På Unix-kompatible systemer (-I er valgfri i POSIX og kun krævet til UNIX-kompatible systemer), skal du forbehandle input til citat linjerne i det format, der forventes af xargs:
< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args
Bemærk dog, at nogle xargs implementeringer har en meget lav grænse for argumentets maksimale størrelse (f.eks. 255 på Solaris, det minimum, der er tilladt i Unix-specifikationen).
Kommentarer
Svar
Holder nøjagtigt til spørgsmå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
- fungerede som charme 🙂
- +1 elskede dette tak
Svar
Det bedste svar jeg har und er:
for i in `cat`; do "$cmd" "$i"; done < $file
EDIT:
… fire år senere …
efter flere nedstemninger og lidt mere erfaring, vil jeg anbefale følgende nu:
xargs -l COMMAND < file
Kommentarer
- Dette påkalder kommandoen en gang for hvert ord i filen. Du bør også altid citere henvisninger til shellvariabler (som i
do "$cmd" "$i";), medmindre du har en grund til ikke at; hvis filen indeholdt en*som et ord i sig selv, ville din kode køre$cmd *, hvilket naturligvis ville køre kommandoen med en liste over filerne i den aktuelle mappe. - @ G-Man, undtagen i
zsh,`cat`ville allerede udvide*(den ikke-citerede$ikunne stadig udvide noget jokertegn (en anden runde), hvis udvidelsen af`cat`introducerer nogle). Under alle omstændigheder er denne tilgang faktisk forkert. - +1. Dette fungerer fint, hvis hver linje kun indeholder det input, der er nødvendigt for kommandoen, der bruges uden mellemrum.
- +1, kunne lide xargs-løsning
- Dette fungerer! (den senere redigering
xargs -l COMMAND < file). Tak!
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
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
Svar
ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt
Tag alle de linjer i en fil og videresende dem som argumenter til en enkelt kommando, dvs.
command line1 line2 line3 ....
Hvis du har brug for --option flag forud for hver linje, skift den anden kommando til:
%g/^/s// --option /
Kommentarer
- Hvad -1 for bruger ed … virkelig?
- Jeg ' t nedstemte dig, men den person, der sandsynligvis havde følgende grunde: (1) Dette gør det ikke hvad spørgsmålet beder om. Dette påkalder kommandoen en gang med alt indholdet af filen på kommandolinjen; snarere end en gang pr. linje .(2) Dette håndterer intet for at håndtere tegn, der er specielle for skallen (der kan være i filen); f.eks.
',",<,>,;osv. (3) Dette skaber en unødvendig midlertidig fil. (4) Ting som dette gøres generelt med “her dokumenter”. (5) Dineedkommandoer er klodset; de to første kommandoer kan reduceres til%s/^/ /og%j.
<file xargs -L 1 -I{} command --option {} other args