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$i
kunne 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) Dineed
kommandoer er klodset; de to første kommandoer kan reduceres til%s/^/ /
og%j
.
<file xargs -L 1 -I{} command --option {} other args