Mam następujący prosty skrypt, w którym uruchamiam pętlę i chcę zachować plik COUNTER
. Nie mogę zrozumieć, dlaczego licznik się nie aktualizuje. Czy jest to spowodowane tworzeniem podpowłoki? Jak mogę to potencjalnie naprawić?
#!/bin/bash
WFY_PATH=/var/log/nginx
WFY_FILE=error.log
COUNTER=0
grep 'GET /log_' $WFY_PATH/$WFY_FILE | grep 'upstream timed out' | awk -F ', ' '{print $2,$4,$0}' | awk '{print "http://domain.com"$5"&ip="$2"&date="$7"&time="$8"&end=1"}' | awk -F '&end=1' '{print $1"&end=1"}' |
(
while read WFY_URL
do
echo $WFY_URL #Some more action
COUNTER=$((COUNTER+1))
done
)
echo $COUNTER # output = 0
Odpowiedzi:
Po pierwsze, nie zwiększasz licznika. Zmiana
COUNTER=$((COUNTER))
naCOUNTER=$((COUNTER + 1))
lubCOUNTER=$[COUNTER + 1]
zwiększy to.Po drugie, jak przypuszczasz, trudniej jest propagować zmienne podpowłoki do wywoływanego. Zmienne w podpowłoce nie są dostępne poza podpowłoką. Są to zmienne lokalne dla procesu potomnego.
Jednym ze sposobów rozwiązania tego problemu jest użycie pliku tymczasowego do przechowywania wartości pośredniej:
źródło
$[...]
jest przestarzałe? Czy istnieje alternatywne rozwiązanie?$[...]
był używanybash
wcześniej$((...))
przez powłokę POSIX. Nie jestem pewien, czy kiedykolwiek był formalnie przestarzały, ale nie mogę znaleźć o nim wzmianki nabash
stronie podręcznika i wydaje się, że jest obsługiwany tylko w celu zapewnienia zgodności wstecznej....
TESTOWANY BASH: Centos, SuSE, RH
źródło
$[ ]
składnia jest przestarzała. stackoverflow.com/questions/10515964/…jest dość niezdarną konstrukcją w nowoczesnym programowaniu.
wygląda bardziej „nowocześnie”. Możesz także użyć
jeśli uważasz, że poprawia to czytelność. Czasami Bash daje zbyt wiele sposobów robienia rzeczy - myślę, że filozofia Perla - kiedy być może Python „jest tylko jeden właściwy sposób, aby to zrobić” może być bardziej odpowiedni. To dyskusyjne stwierdzenie, jeśli kiedykolwiek istniało! W każdym razie sugerowałbym, że celem (w tym przypadku) jest nie tylko inkrementacja zmiennej, ale (zasada ogólna) również napisanie kodu, który ktoś inny może zrozumieć i wesprzeć. Zgodność pozwala to osiągnąć.
HTH
źródło
Spróbuj użyć
zamiast
źródło
let "COUNTER++"
(( COUNTER++ ))
(bez znaku dolara)(( COUNTER++ ))
ale kiedy się naCOUNTER=$((COUNTER + 1))
niego przełączyłem , zadziałał.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Myślę, że to pojedyncze wywołanie awk jest równoważne z twoim
grep|grep|awk|awk
potokiem: przetestuj go. Wydaje się, że Twoje ostatnie polecenie awk nic nie zmienia.Problem z COUNTER polega na tym, że pętla while działa w podpowłoce, więc wszelkie zmiany w zmiennej znikają po zakończeniu działania podpowłoki. Musisz uzyskać dostęp do wartości COUNTER w tej samej podpowłoce. Lub skorzystaj z porady @ DennisWilliamson, użyj podstawienia procesu i całkowicie unikaj podpowłoki.
źródło
źródło
Zamiast używać pliku tymczasowego, można uniknąć tworzenia podpowłoki wokół
while
pętli, używając podstawiania procesów.Nawiasem mówiąc, powinieneś być w stanie przekształcić to wszystko
grep, grep, awk, awk, awk
w jedenawk
.Począwszy od Bash 4.2, istnieje
lastpipe
opcja, któraźródło
lastpipe
. Swoją drogą, prawdopodobnie powinieneś użyć"${PIPESTATUS[@]}"
(at zamiast gwiazdki).minimalistyczny
źródło
To wszystko, co musisz zrobić:
Oto fragment książki Learning the bash Shell , wydanie trzecie, str. 147, 148:
..........................
Zobacz http://www.safaribooksonline.com/a/learning-the-bash/7572399/
źródło
if
stwierdzenia:if [[ $((needsComma++)) -gt 0 ]]; then printf ',\n'; fi
dobrze czy źle, to jedyna wersja, która działała niezawodnie.i=1; while true; do echo $((i++)); sleep .1; done
if (( needsComma++ > 0 )); then
lubif (( needsComma++ )); then
To jest prosty przykład
źródło
Wygląda na to, że nie zaktualizowałeś
counter
skryptu, użyjcounter++
źródło
Były dwa warunki, które spowodowały, że wyrażenie
((var++))
zawiodło:Jeśli ustawię bash na tryb ścisły (
set -euo pipefail
) i jeśli zacznę mój przyrost od zera (0).Rozpoczynanie od jednego (1) jest w porządku, ale zero powoduje, że przyrost zwraca „1” podczas oceny „++”, co jest niezerowym błędem kodu powrotu w trybie ścisłym.
Mogę użyć
((var+=1))
lubvar=$((var+1))
uciec od tego zachowaniaźródło
Skrypt źródłowy ma problem z podpowłoką. Pierwszy przykład, prawdopodobnie nie potrzebujesz podpowłoki. Ale nie wiemy, co kryje się pod hasłem „Jeszcze więcej akcji”. Najpopularniejsza odpowiedź ma ukryty błąd, który zwiększy I / O i nie będzie działał z podpowłoką, ponieważ przywraca wewnętrzną pętlę coutera.
Nie dodawaj znaku '\', poinformuje on interpretera basha o kontynuacji linii. Mam nadzieję, że pomoże to Tobie lub komukolwiek. Ale moim zdaniem ten skrypt powinien zostać w pełni przekonwertowany do skryptu AWK lub przepisany do Pythona przy użyciu regexp lub perl, ale popularność perla przez lata spada. Lepiej zrób to za pomocą Pythona.
Poprawiona wersja bez podpowłoki:
Wersja z podpowłoką, jeśli jest naprawdę potrzebna
źródło