Jak przeanalizować każdy wiersz pliku tekstowego jako argument polecenia?

Chcę napisać skrypt, który jako argument przyjmuje .txt nazwę pliku i odczytuje wiersz pliku po linii i przekazuje każdą linię do polecenia. Na przykład uruchamia command --option "LINE 1", a następnie command --option "LINE 2" itd. Dane wyjściowe polecenia jest zapisywane w innym pliku. Jak mam to zrobić? Nie wiem, od czego zacząć.

Odpowiedź

Użyj pętli while read:

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

Innym jest przekierowanie wyjścia według bloku:

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

Na koniec otwórz plik:

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 

Jeśli jedno z poleceń odczytuje dane wejściowe, byłoby dobrze pomysł użycia innego fd do wprowadzania danych, aby polecenia nie „zjadły” (tutaj zakładając ksh, zsh lub bash dla -u 3, użyj <&3 zamiast przenośnie):

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

Fin sojusznik, aby akceptować argumenty, możesz zrobić:

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

Który z nich mógłby działać jako:

bash script.sh file another_file 

Dodatkowy pomysł. W przypadku bash użyj readarray:

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

Uwaga: IFS= można pominąć, jeśli nie masz nic przeciwko obcięciu wartości linii ze spacji wiodących i końcowych.

Odpowiedź

Inną opcją jest xargs.

Z GNU xargs:

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

{} to symbol zastępczy wiersza tekstu.

Inne xargs generalnie nie” nie ma -a, -d, ale niektóre mają -0 dla wejścia rozdzielanego wartością NUL. Dzięki nim możesz:

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

W systemach zgodnych z Uniksem (-I jest opcjonalne w POSIX i tylko wymagane dla systemów zgodnych z UNIX), „musiałbyś wstępnie przetworzyć dane wejściowe, aby cytować wiersze w formacie oczekiwanym przez xargs:

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

Należy jednak pamiętać, że niektóre xargs implementacje mają bardzo niski limit maksymalnego rozmiaru argumentu (na przykład 255 w Solarisie, minimum dozwolone przez specyfikację Unix).

Komentarze

  • redukowalne do <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, nie, to przetworzyłoby cudzysłowy i usunąłoby niektóre spacje.

Odpowiedź

Dokładne zachowanie do pytania:

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

Komentarze

  • działał jak czarujący 🙂
  • +1 bardzo mi się podobało, dzięki

Odpowiedź

Najlepsza odpowiedź, jaką mam und is:

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

EDYCJA:

… cztery lata później …

po kilku głosach negatywnych i nieco większym doświadczeniu polecam teraz:

xargs -l COMMAND < file 

Komentarze

  • Spowoduje to wywołanie polecenia raz dla każdego słowa w pliku. Powinieneś także zawsze cytować odniesienia do zmiennych powłoki (jak w do "$cmd" "$i";), chyba że masz powód, aby tego nie robić; jeśli plik zawierałby * jako samo słowo, kod działałby $cmd *, co oczywiście uruchomiłoby polecenie z lista plików w bieżącym katalogu.
  • @ G-Man, z wyjątkiem zsh, `cat` rozwinąłby już * (niecytowany $i mógłby nadal rozwinąć jakiś symbol wieloznaczny (druga runda), gdyby rozwinięcie `cat` wprowadza niektóre). W każdym razie takie podejście jest rzeczywiście błędne.
  • +1. To zadziała dobrze, jeśli każda linia zawiera tylko dane wejściowe potrzebne dla używanego polecenia bez spacji.
  • +1, polubione rozwiązanie xargs
  • To działa! (późniejsza edycja xargs -l COMMAND < file). Dzięki!

Odpowiedź

 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 

Odpowiedź

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

Weź wszystkie wiersze pliku i przekaż je jako argumenty do pojedynczego polecenia, np.

command line1 line2 line3 .... 

Jeśli potrzebujesz --option flaga poprzedzająca każdą linię zmień drugie polecenie na:

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

Komentarze

  • Po co -1 używając ed … naprawdę?
  • Nie ' nie głosowałem przeciw, ale osoba, która to zrobiła, prawdopodobnie miała następujące powody: (1) To nie działa o co chodzi w pytaniu. Powoduje to jednokrotne wywołanie polecenia z całą zawartością pliku w wierszu poleceń; zamiast raz w wierszu .(2) To nie robi nic, aby obsłużyć znaki, które są specjalne dla powłoki (które mogą znajdować się w pliku); np. ', ", <, >, ;, itd. (3) Tworzy to niepotrzebny plik tymczasowy. (4) Takie rzeczy są zwykle wykonywane z „dokumentami tutaj”. (5) Twoje ed polecenia są niezgrabne; pierwsze dwa polecenia można zredukować do %s/^/ / i %j.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *