Bash: Объем переменных в цикле for с использованием тройника

Рассматривать:

numbers="1 111 5 23 56 211 63" max=0 for num in ${numbers[@]}; do [ $num -gt $max ]\ && echo "old -> new max = $max -> $num"\ && max=$num done | tee logfile echo "Max= $max" 

Если я удалю | tee logfile | tee logfile максимальная переменная правильно напечатана как 211, но если я ее оставлю, я получу Max= 0 .

Что происходит?

3 Solutions collect form web for “Bash: Объем переменных в цикле for с использованием тройника”

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

В bash вместо использования трубы вы можете использовать замену процесса . Это будет вестись почти одинаково с трубой, за исключением того, что цикл выполняется в исходной оболочке, и только tee выполняется в подоболочке.

 for num in "${numbers[@]}"; do if ((num > max)); then echo "old -> new max = $max -> $num" max=$num fi done > >(tee logfile) echo "Max= $max" 

Пока я был в этом, я изменил несколько вещей в вашем скрипте:

  • Всегда используйте двойные кавычки вокруг переменных замещений, если вы не знаете, почему их нужно оставить.
  • Не используйте && если вы имеете в виду, if . Это менее читаемо и не имеет такого же поведения, если используется статус возврата команды.
  • Поскольку я использую конструкторы, специфичные для bash, я мог бы также использовать арифметический синтаксис .

Обратите внимание, что между решением трубы и решением подоболочки существует небольшая разница: команда команды заканчивается, когда обе команды завершаются, тогда как команда с замещением процесса заканчивается, когда основная команда завершается, не дожидаясь процесса в замещении процесса. Это означает, что когда ваш скрипт заканчивается, файл журнала может быть не полностью записан.

Другой подход – использовать другой канал для связи от подоболочки к исходному процессу оболочки. Вы можете использовать временный файл (гибкий, но сложнее сделать правильно – записать временный файл в соответствующий каталог, избежать конфликтов имен (используйте mktemp ), удалить его даже в случае ошибок). Или вы можете использовать другой канал для передачи результата и захвата результата в подстановке команд.

 max=$({ { for … done; echo "$max" >&4 } | tee logfile >&3; } 4>&1) 3&>1 

Выход tee переходит к файловому дескриптору 3, который перенаправляется на стандартный вывод сценария. Вывод echo "$max" относится к файловому дескриптору 4, который перенаправляется в подстановку команд.

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

Он не переживает трубы, но это работает:

 numbers="1 111 5 23 56 211 63" max=0 echo $max>maxfile for num in ${numbers[@]}; do [ $num -gt $max ]\ && echo "old -> new max = $max -> $num"\ && max=$num\ && echo $max>maxfile done | tee logfile read max<maxfile echo "Max= $max" 
  • Как присвоить значение переменной, когда значение содержит символ $ в ней
  • Расширение «$ @» для пользовательских переменных
  • Установка переменной, значение которой зависит от другой переменной
  • grep переменная в выражении if
  • dirname и basename против расширения параметров
  • Как использовать тройник для захвата STDOUT из кодового блока в имя файла, определенное в блоке?
  • Использование sed в сценарии оболочки с многострочными переменными
  • Невозможно назначить вывод вложенных команд переменной в bash
  • Как сопоставить текст между строкой и пробелом
  • Функция проверки переменной BASH
  • Как добавить текст в переменную в make-файле?
  • Interesting Posts

    Может кто-нибудь уточнить этот сценарий Bash

    Как отключить проверки переносов порталов

    Ошибка аутентификации Mutt, поскольку строка имени пользователя неверна

    Как я могу форматировать вывод команды оболочки

    Debian Lenny Server скомпрометирован – нет знака точки вторжения?

    Как использовать канал для назначения переменной

    Неовим цветовая гамма в Urxvt неправильно рендерится

    Хостинг на Apache / 2.2.22, сканирование говорит об устаревших

    Возможно ли повторное использование оболочки?

    Найти файл с более длинным именем

    SSH на сервер, выполните команду обновления, которая продолжается даже после выхода из сеанса ssh

    Синхронизация двух компьютеров с унисон и ssh

    Являются ли FIFO, pipe & Unix доменными сокетами одинаковыми в ядре Linux?

    Необходимо подключиться к порту через LAN через межсетевой экран IPTABLES на статическом IP-интерфейсе

    Как обратная косая черта динамической строки в bash

    Linux и Unix - лучшая ОС в мире.