LINUX.ORG.RU

Переменная по выходу из цикла превращается в ноль

 , ,


0

3

Тупейшая задача — найти наибольшее значение. Если быть точным — длину наидлиннейшей строки в файле. Где тут, кот меня пожри, можно ошибиться?

maxLen=0; # начальное значение
while ...; do # смотрим множество значений
    gotLineLen=...; # берём очередное значение
    if [ "$maxLen" -lt "$gotLineLen" ]; then
        echo "Отладка: точка алогритма: " \
            "присваиваем найденное значение $gotLineLen... ";
        maxLen="$gotLineLen";
        echo "Отладка: обзор переменных: maxLen=$maxLen";
    fi;
done;
echo "ВНИМАНИЕ: строчкой ниже - разрыв шаблона!";
echo "Отладка: обзор переменных: maxLen=$maxLen";
Вывод:
Отладка: точка алогритма:  присваиваем найденное значение 14... 
Отладка: обзор переменных: maxLen=14
ВНИМАНИЕ: строчкой ниже - разрыв шаблона!
Отладка: обзор переменных: maxLen=0
Полный исходник
Вывод

ЛОР, ткни меня мордой, где я дебил?

адовый говнокод

anonymous
()

Цикл выполняется в сабшелле, ЕМНИП. Все значения по выходу из сабшелла теряются.

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

E ★★★
()
Ответ на: комментарий от Northsoft
max_len = ''
with open('file', 'r') as f:
    for line in f:
        if len(line) > len(max_len):
            max_len = line

пример на питоне.

conformist ★★★
()
Ответ на: комментарий от Northsoft

Вообще-то приведённый тобой код к примеру от 'alozovskoy' никак не относится, а 'Е' говорит неправду.
На этом фрагменте ошибка не воспроизводится, так что ты где-то лукавишь. Попробуй написать реальный (без '...') пример и выложи.

ABW ★★★★★
()
Ответ на: комментарий от E

Цикл выполняется в сабшелле, ЕМНИП.

Сфигли бы? Где вы здесь подоболочку увидели?

Zmicier ★★★★★
()

УМВР. Давайте настоящую программу, без пропусков.

echo "Отладка: обзор переменных: maxLen=$maxLen"

Отладке не место на стандартном выводе, для нее есть вывод ошибки.

debug() {
    printf >&2 'Отладка: %s\n' "$*"
}

debug "maxLen=$maxLen"
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Полный исходник

А! Блин, не надо так больше делать, мы не в IRC.

Там у вас лежит следующее:

    #!/bin/bash

    outputFileName='output.txt';

    # удаляем файл с предыдущим результатом
    if [ -f "$outputFileName" ]; then
        rm --verbose --force "$outputFileName";
    fi;

    filelist=`mktemp`;

    # ограничиваем поиск двумя результатами, этого достаточно, чтобы увидеть эффект
    find -maxdepth 1 -type f > "$filelist";
    cat "$filelist" | head -n 2 | while read fileNameLine
    do
        echo "Отладка: точка алгоритма: просматриваем файл $fileNameLine";
        maxLen=0;
        cat "$fileNameLine" | while read fileContentLine
        do
            gotLineLen=`echo "$fileContentLine" | wc --bytes`;
            echo "Отладка: точка алгоритма: начинаем обрабатывать строку";
            echo "Отладка: обзор переменных: " \
                "maxLen=$maxLen (сохранённая длина), " \
                "gotLineLen=$gotLineLen (найденная длина)";
            if [ "$maxLen" -lt "$gotLineLen" ]; then
                echo "Отладка: точка алогритма: " \
                    "присваиваем найденное значение $gotLineLen... ";
                maxLen="$gotLineLen";
                echo "Отладка: обзор переменных: maxLen=$maxLen";
            fi;
            echo "Отладка: точка алгоритма: закончили обрабатывать строку";
            echo;
        done;
        echo "ВНИМАНИЕ: строчкой ниже - разрыв шаблона!";
        echo "Отладка: обзор переменных: maxLen=$maxLen";
        echo "Отладка: точка алгоритма: закончили смотреть файл";
        echo -e "\n";
        if [ "$maxLen" -gt 0 ]; then
            echo "Результат: $maxLen: $fileNameLine";
        fi;
        echo
    done;
    rm -vf "$filelist";

Да, E, прощу прощения, здесь цикл конечно же в подоболочке.

И да, не могу не согласится с анонимом, говнокод действительно адовый. Вы определеяете размер файла, записывая его целиком в переменную что ли (gotLineLen=`echo "$fileContentLine" | wc --bytes`;)? O_o

Расскажите нормально, что вам нужно?

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 3)
Ответ на: комментарий от Zmicier

Расскажите нормально, что вам нужно?

Если быть точным — длину наидлиннейшей строки в файле.


И ещё.

А! Блин, не надо так больше делать, мы не в IRC.

Лично меня — бесит, когда ОП выкладывает сотню–тысячу строк мне в ленту.

Northsoft ★★
() автор топика

длину наидлиннейшей строки в файле

Не мучь себя

wc -L path/to/file

znenyegvkby
()
Последнее исправление: znenyegvkby (всего исправлений: 1)
Ответ на: комментарий от Zmicier
debug() {
    printf >&2 'Отладка: %s\n' "$*"
}

Так тоже не стоит делать — теряется статус прошлой команды и генерируется лишний CHLD, где-то может выстрелить.

DonkeyHot ★★★★★
()
Ответ на: комментарий от DonkeyHot

Так тоже не стоит делать

И как же по-вашему сто́ит делать?

теряется статус прошлой команды

Не понял проблемы.

и генерируется лишний CHLD

???

Во-первых, в неинтерактивном ГНУ Баше управление задачами вообще-то по-умолчанию отключено, то есть не то, что на лишние, а вообще на все CHLD ему пофиг.

А во-вторых, CHLD — это сигнал о завершении дочернего процесса; где вы здесь дочерний процесс усмотрели?

где-то может выстрелить.

И где же?

Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

что-то типа:

debug() {
local rc=$?
дебажный код
return $rc
}

где вы здесь дочерний процесс усмотрели

Ошибся, думал, что printf не встроен. Да и вообще, shell - не то место, где лишние потомки должны быть критичны, т.ч. нужно очень неосторожно писать. Про CHLD отзываю.

DonkeyHot ★★★★★
()
Ответ на: комментарий от Zmicier

И где же?

Да, забыл. «Простой» дебаг нельзя вставлять куда попало: перед любым использованием «$?» или внутри «a && b || c» - поломает логику.

DonkeyHot ★★★★★
()

На сишарпе в одну строчку: File.ReadAllLines(@«path»).Select(line => line.Length).Max()

На руби в одну строчку: File.open(«path»,«r»).readlines.map { |line| line.length }.max

nikolnik ★★★
()
Ответ на: комментарий от DonkeyHot

local rc=$?
return $rc

Дело пахнет костылями.

нельзя вставлять куда попало

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

внутри a && b || c

Эта конструкция сама по себе неплохой источник косяков, ибо многие почему-то свято уверены, что это тернарный оператор типа if-then-else, хотя вовсе нет.

Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

вставить прям посередь условия

Проблема в том, что достаточно перед условием.

Эта конструкция сама по себе неплохой источник косяков

Программирование вообще - источник косяков, но это не повод не писать:).

DonkeyHot ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.