Подтвердить что ты не робот

Переменные оболочки, находящиеся внутри цикла, не видны вне его

Я пытаюсь найти путь с наибольшим количеством символов в нем. Там могут быть лучшие способы сделать это. Но я хотел бы знать, почему эта проблема возникает.

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

Он как-то всегда возвращает:

0 :

Если я распечатываю результаты для отладки внутри цикла while, значения верны. Итак, почему bash не делает эти переменные глобальными?

4b9b3361

Ответ 1

Когда вы подключаетесь к циклу while в Bash, он создает подоболочку. Когда подоболочка выходит, все переменные возвращаются к своим предыдущим значениям (которые могут быть нулевыми или неустановленными). Это может быть предотвращено с помощью замены процесса.

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

Ответ 2

"Правильный" ответ задается Dennis. Тем не менее, я считаю, что подстановка подстановки процесса чрезвычайно нечитаема, если цикл содержит более нескольких строк. При чтении script, я хочу посмотреть, что происходит в трубе, прежде чем я увижу, как он обрабатывается.

Поэтому я обычно предпочитаю этот трюк инкапсуляции цикла while в "{}".

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
}

Ответ 3

Об обнаружении самого длинного пути. Вот альтернатива:

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

Простите меня, если это считается не по теме, я надеюсь, что это поможет кому-то.

Ответ 4

Делайте то, что вы всегда (должны) делать:

  • отдельные проблемы,
  • избегать глобальных привязок,
  • запишите свой код,
  • можно читать,
  • может быть POSIXy.

(Да, я добавил немного добавочных ингредиентов к супу, чем это абсолютно необходимо;))

Итак, моя любимая реакция "колено-рывок" на проблемы с невидимой подоболочкой заключается в использовании функции:

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

Кроме того, чтобы избежать раздражения подоболочки, он дает вам идеальное место для документирования кода и сортировки добавляет пространство имен: обратите внимание, что внутри функции вы можете использовать гораздо более короткие и простые имена переменных, не теряя при этом удобочитаемости.