Przetwarzanie rozdzielonego pliku tekstowego w bash jako argumenty polecenia

10

Mam podzielony plik tekstowy:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Każda z tych kolumn będzie parametrem programu i chciałbym, aby program był wywoływany dla każdej linii

Miałem nadzieję na pętlę, coś w stylu:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Jaki byłby najlepszy sposób na osiągnięcie czegoś takiego w bash?

Dziekan
źródło
Czy liczba pól jest stała?
Joseph R.
@JosephR. tak są, zawsze 3
Dziekan

Odpowiedzi:

7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Powinno to działać, jeśli liczba pól jest stała. Zamiast echoużywać polecenia.

kubek kawy
źródło
Dzięki, właśnie próbowałem tego, ale wydaje się, że działa tylko na pierwszą linię. Gdy tylko komenda się powiedzie, nie spróbuje następnej, jeśli się nie powiedzie, spróbuje jednak następnej ...
Dziekan
Jak rozumiesz sukces czy porażkę? Czym zajmuje się twoje polecenie?
coffeMug
Domyślam się, że polecenie, które wykonuje, odczytuje standardowe dane wejściowe, zanim komenda „czytaj” może je odczytać.
płyn do płukania
4

Powinieneś używać whilez readwbudowanym:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Jak to działa

  • cutOświadczenie zajmuje linię i dzieli go na wskazany przez ogranicznik -d.
  • Jest --output-delimiterto znak separatora, który cutbędzie używany do wyświetlania wybranych pól, tutaj wybieramy spację, abyśmy mogli umieścić różne pola w tablicy fields.
  • Wreszcie, chcemy wszystkich pól (od pola 1 do końca) i tam właśnie -f1-wchodzi w grę.
  • Teraz, gdy masz różne pola przechowywane w zmiennej tablicowej fields, możesz uzyskać dostęp do dowolnego pola, którego chcesz, dzięki składni, ${field[number]}gdzie numberjest o jeden mniej niż rzeczywista liczba pól, którą chcesz, ponieważ indeksowanie tablic w Bash jest zerowane.

Uwaga

  • To się nie powiedzie, jeśli któreś z pól zawiera spacje.

Dla stałej liczby pól

Zamiast tego możesz zrobić coś podobnego do odpowiedzi 1_CR :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

Powyższe, choć wydaje się bardziej hałaśliwe, powinno działać w dowolnej powłoce zgodnej z POSIX, nie tylko w Bash.

Joseph R.
źródło
Nie czytam w pliku, z którym mam problem, dzieli linię na kolumny.
Dziekan
@Dean Tak, przepraszam. Nie zwracałem uwagi. Pracuję nad tym teraz.
Joseph R.
@Dean Zobacz zaktualizowaną odpowiedź. Wkrótce dodam wyjaśnienie.
Joseph R.
@JosephR., Można uniknąć używania zewnętrznych narzędzi do dzielenia, ustawiając IFSodpowiednią wartość w readwywołaniu
iruvar
@ 1_CR Wiem, dziękuję. Właśnie do tego doszedłem :)
Joseph R.
1

Możesz readpodzielić każdą linię na tablicę ,, ustawiając IFSodpowiednio.

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

W powyższym przykładzie możesz uzyskać dostęp do każdego elementu tablicy za pomocą jego indeksu, zaczynając od 0.

iruvar
źródło
1

Ten awkliniowiec zrobi, co chcesz:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Zastąp echopoleceniem i f.txtplikiem, który chcesz iterować.

Krótkie wyjaśnienie: -F,ustawi się ,jako separator. cmdbuduje polecenie i system(cmd)wywołuje polecenie.

mkc
źródło
1

gnu sed może być również używany.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

zauważ użycie opcji e do polecenia s

Hildred
źródło