/ / Zmienne powłoki ustawione wewnątrz, pętla niewidoczna poza tym - bash

Zmienne powłoki ustawione wewnątrz, pętla niewidoczna poza tym - bash

Próbuję znaleźć ścieżkę z największą liczbą znaków. Mogą być lepsze sposoby na zrobienie tego. Ale chciałbym wiedzieć, dlaczego ten problem występuje.

LONGEST_CNT=0
find samples/ | while read line
do
line_length=$(echo $line | wc -m)
if [[ $line_length -gt $LONGEST_CNT ]]
then
LONGEST_CNT=$line_length
LONGEST_STR=$line
fi
done

echo $LONGEST_CNT : $LONGEST_STR

Jakoś zawsze wraca:

0 :

Jeśli wydrukuję wyniki do debugowania wewnątrz pętli while, wartości są poprawne. Dlaczego bash nie czyni tych zmiennych globalnymi?

Odpowiedzi:

72 dla odpowiedzi nr 1

Po podłączeniu do while loop w Bash, tworzy podpowłokę. Po zakończeniu podpowlekania wszystkie zmienne powracają do swoich poprzednich wartości (które mogą być puste lub anulowane). Można temu zapobiec, stosując proces zastępowania.

LONGEST_CNT=0
while read -r line
do
line_length=${#line}
if (( line_length > LONGEST_CNT ))
then
LONGEST_CNT=$line_length
LONGEST_STR=$line
fi
done < <(find samples/ )    # process substitution

echo $LONGEST_CNT : $LONGEST_STR

20 dla odpowiedzi nr 2

"Poprawna" odpowiedź jest podana przez Dennis. Jednak znajduję sztuczkę zastępującą procesbardzo nieczytelne, jeśli pętla zawiera więcej niż kilka linii. Czytając skrypt, chcę zobaczyć, co dzieje się w rurze, zanim zobaczę, jak jest przetwarzany.

Więc zwykle wolę tę sztuczkę enkapsulacji pętli while w "{}".

LONGEST_CNT=0
find /usr/share/zoneinfo | 
{ while read -r line
do
line_length=${#line}
if (( line_length > LONGEST_CNT ))
then
LONGEST_CNT=$line_length
LONGEST_STR=$line
fi
done
echo $LONGEST_CNT : $LONGEST_STR
}

2 dla odpowiedzi nr 3

O znalezieniu najdłuższej ścieżki. Oto alternatywa:

find /usr/share/zoneinfo | while read line; do
echo ${#line} $line
done | sort -nr | head -n 1

# Result:
58 /usr/share/zoneinfo/right/America/Argentina/ComodRivadavia

Przebacz mi, jeśli nie jest to temat, mam nadzieję, że komuś pomoga.


0 dla odpowiedzi nr 4

Rób to, co zawsze (powinno) robić:

  • oddzielne problemy,
  • unikaj globali,
  • udokumentuj swój kod,
  • nadać się,
  • może być POSIXy.

(Tak, dodałem do zupy nieco więcej "dobrych praktyk" niż to absolutnie konieczne;))

Więc moją ulubioną "reakcją odruchową" na problemy z niewidzialną podpowłoką jest użycie funkcji:

#!/bin/sh

longest() {
#
# Print length and body of the longest line in STDIN
#
local cur_ln    # current line
local cur_sz    # current size (line length)
local max_sz    # greatest size so far
local winner    # longest string so far
max_sz=0
while read -r cur_ln
do
cur_sz=${#cur_ln}
if test "$cur_sz" -gt "$max_sz";
then
max_sz=$cur_sz
winner=$cur_ln
fi
done
echo "$max_sz" : "$winner"
}

find /usr/share/zoneinfo | longest

# ok, if you really wish to use globals, here you go ;)
LONGEST_CNT=0
LONGEST_CNT=$(
find /usr/share/zoneinfo 
| longest 
| cut -d: -f1 
| xargs echo
)
echo "LONGEST_CNT="$LONGEST_CNT""

Oprócz uniknięcia irytacji podpórki, todaje idealne miejsce do udokumentowania kodu i sortowania - dodaje przestrzeń nazw: zauważ, że wewnątrz funkcji możesz używać znacznie krótszych i prostszych nazw zmiennych bez utraty czytelności.