Polecenie awk w pętli for

Próbuję, bez powodzenia, użyć polecenia awk w for pętla.

Mam zmienną zawierającą serię ciągów, które chcę wyciąć za pomocą awk aby uzyskać dane.

Wiem, jak to zrobić, ale naprawdę chcę wycinać dane sukcesywnie.

Mam więc zmienną:

var="data1,data2,data3" 

I tutaj jestem teraz:

for ((i=1; i<=3; i++)) do echo $(awk -F, "{print $1}" <<< $var) done 

Próbuję zastąpić $1 przez pętlę $i ale bez powodzenia.

Komentarze

  • Każdy znak pomiędzy parą pojedynczych cudzysłowów jest traktowany jako znak dosłowny.
  • Jaki jest Twój prawdziwy przypadek użycia? pętla po awk wydaje się tutaj niepotrzebna (na przykład w bashu można użyć podstawienia parametru echo "${var//,/$'\n'}")
  • W rzeczywistości zmienna będzie zawierała adresy URL z postaci zenity. Chcę używać tych adresów URL osobno, więc muszę pobrać każdy z nich niezależnie.
  • Odpowiednie, ale nie jest to dobre rozwiązanie w tym przypadku: Jak to zrobić przypisać wartość w czasie wykonywania w poleceniu AWK

Odpowiedź

Możesz osiągnąć to, co „re próbując to zrobić, używając podwójnych cudzysłowów w skrypcie awk, aby wstrzyknąć do niego zmienną powłoki. Nadal chcesz zachować w nim jeden literał $, co możesz zrobić, zapisując go ukośnikiem odwrotnym :

echo $(awk -F, "{print \$$i}" <<<$var) 

Spowoduje to rozwinięcie $i do 1, 2 i 3 w każdej z iteracji, dlatego awk zobaczy $1, $2 i $3, co spowoduje rozszerzenie każdego z pól.

Inną możliwością jest wprowadzenie zmiennej powłoki jako awk z użyciem flagi -v :

echo $(awk -F, -v i="$i" "{print $i}" <<<$var) 

To przypisuje zmienną awk i do zawartości zmiennej powłoki o tej samej nazwie. Zmienne w awk nie używają elementu $, który jest używany w polach, więc $i wystarczy, aby odwołać się do i -te pole, jeśli i jest zmienną w awk.

Przypisanie zmiennej awk za pomocą -v jest ogólnie bezpieczniejsze podejście, szczególnie gdy może zawierać dowolne sekwencje znaków, w takim przypadku istnieje mniejsze ryzyko, że zawartość zostanie wykonana jako kod awk wbrew twoim zamiarom. Ale ponieważ w twoim przypadku zmienna zawiera jedną liczbę całkowitą, nie ma to większego znaczenia.

Jeszcze inną opcją jest użycie pętli for w samym awk . Zapoznaj się z dokumentacją awk (lub przeszukaj tę witrynę), aby uzyskać więcej informacji o tym, jak to zrobić.

Komentarze

  • … lub ustaw rekord wejściowy separator odpowiednio awk -v RS='[,\n]' 1 <<< "$var" (a może bardziej przenośny printf "$var" | awk -v RS=, 1)
  • @steeldriver Ten skrypt awk wypisze wszystkie trzy pola w Co jest w porządku, biorąc pod uwagę, że OP robi tylko to … Skoncentrowałem się w odpowiedzi na wyodrębnieniu pojedynczego pola przy założeniu, że byli zainteresowani wykonaniem innych poleceń w pętli powłoki (co może były motywacją do użycia jednego w pierwszej kolejności …)
  • Zrozumiałem – że ' dlaczego skomentowałem PO, aby wyjaśnić, co naprawdę chcę zrobić;)
  • pierwszy to zastrzyk (i problem bezpieczeństwa), drugi o ne (using -v) nie jest zastrzykiem.
  • Dzięki, Twoja odpowiedź rozwiązała mój problem! Pierwszy raz zadaję tutaj pytanie po latach czytania postów. Nie zawiodłem się. Taka wspaniała społeczność!

Odpowiedź

Używanie awk wydaje się nadmierna w tej sytuacji, a co powiesz na tr i pętlę while:

tr , "\n" <<<"$var" | while read; do echo $REPLY done 

Dane wyjściowe:

data1 data2 data3 

Komentarze

  • Świetnie. REPLY to domyślny name argument dla read wbudowanego polecenia powłoki.
  • Zauważ, że wymaga to, aby powłoka używała domyślnej zmiennej do umieszczania danych z read, co zdarza się robić bash , ale to nie jest standard. Ponadto polecenie read może modyfikować dane, jeśli zawiera odwrotne ukośniki, i może usuwać flankujące białe znaki z wartości. Odczytuje również wartości z osadzonymi znakami nowej linii jako wiele wartości. Dodatkowo potrzebujesz "$REPLY", aby powstrzymać powłokę przed dzieleniem wartości i wykonywaniem na niej rozwijania nazw plików.

Odpowiedź

może zaakceptować zarówno j (jako zmienna), jak i $j (jako indeks pola):

 for i in 1 2 3; do echo "$var" | awk -v j=$i -F , "{print $j}"; done  

$i w przykładzie„ confused ”awk którego użyć (powłoka lub jej własna zmienna – mają pierwszeństwo), ponieważ obie są określane prefiksem $.

uwaga

, który jest standardem dla „przenośnych” skryptów, nie obsługuje:

(( i=1; i<=3; i++; )) i konstrukcje <<< $var

Możesz również rozważyć użycie polecenia seq w for pętla dla dokładniejszej kontroli generowania sekwencji liczb, jeśli jest dostępna.

Komentarze

  • Twoja pętla działałaby tylko wtedy, gdybyś miał trzy pliki o nazwie , 2 i 3 w bieżącym katalogu. Ponadto w powłoce używane jest rozwijanie zmiennych bez cytowania, co może mieć niepożądane konsekwencje, jeśli dane zawierają wzorce nazw plików (np. *). echo może ponadto modyfikować dane, jeśli zawierają one ukośniki odwrotne.

Odpowiedź

#!/bin/sh var="data1,data2,data3" unset data while [ "$var" != "$data" ]; do data=${var%%,*} # delete first comma and the bit after it var=${var#*,} # delete bit up to first comma (and the comma) printf "data = "%s"\n" "$data" done 

W tym miejscu używamy podstawień zmiennych, aby uzyskać każde kolejne pole danych rozdzielone przecinkami z wartości zmiennej var. Pierwsze przypisanie do data w pętli usunie wszystko z $var po pierwszym przecinku. Zmienna var jest następnie modyfikowana w taki sposób, że usuwany jest pierwszy bit do pierwszego przecinka.

Trwa to do "$var" = "$data" co oznacza, że nic więcej nie można zrobić z łańcuchem.

Ten sposób pozwoliłby nam obsłużyć ciągi danych oddzielone przecinkami, które zawierają osadzone znaki nowej linii:

var="line1 line2,data2,last bit goes here" 

Przy powyższych wartościach w var powyższy skrypt wyświetli wynik

data = "line1 line2" data = "data2" data = "last bit goes here" 

Brak dbałości o osadzone znaki nowej linii; Bardzo rzadko musisz zapętlić wywołania awk.

Zauważ, że awk z wielką przyjemnością odczytuje Twój ciąg jako zbiór pól rozdzielanych przecinkami i że jest w stanie je przeglądać w pętli:

printf "%s\n" "$var" | awk -F "," "{ for (i=1; i<=NF; i++) print $i }" 

Z var="data1,data2,data3", to wypisze

data1 data2 data3 

Kolejne rozwiązanie powłoki, które wykorzystuje IFS zmienna do podzielenia wartości $var na bity, jednocześnie używając set -f do wyłączenia rozwijania nazw plików:

set -f oldIFS=$IFS; IFS="," set -- $var IFS=$oldIFS; unset oldIFS set +f for data do printf "data = "%s"\n" "$data" done 

Dodaj komentarz

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