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

Bash - распространять значение переменной вне цикла

dpkg --list |grep linux-image |grep "ii  " | while read line
do
  arr=(${line})
  let i=i+1
  _constr+="${arr[2]} "
done
echo $i
echo ${_constr}

Операторы echo вне цикла не отображают ожидаемые переменные. Как заставить содержимое переменной распространяться вне цикла?

4b9b3361

Ответ 1

Проблема - это труба, а не цикл. Попробуйте это так.

let i=0
declare -a arr

while read -r line ; do
    arr=(${line})
    let i=i+1
    _constr+="${arr[2]} "
done < <(dpkg --list |grep linux-image |grep "ii  ")

echo $i
echo ${_constr}

Вы также должны предварительно объявить глобальные значения для ясности, как показано выше.

Трубы выполняются в подоболочке, как отмечает Blagovest в своем комментарии. Вместо этого вместо замена процесса (это синтаксис < <(commands)) хранит все в одном процессе, поэтому возможны изменения в глобальных переменных.

Кстати, ваш трубопровод также может быть улучшен

dpkg --list |grep '^ii.*linux-image'

Еще один вызов grep для беспокойства.

Ответ 2

Это несколько обходит ваш вопрос (и это хороший вопрос), но вы можете достичь тех же результатов, используя просто:

 _constr=($(dpkg --list | awk '/^ii.*linux-image/{print $2}'))

Конструкция ($(cmd)) инициализирует массив bash, используя вывод команды внутри.

[[email protected]]$ echo ${_constr[*]}
linux-image-2.6.35-22-generic linux-image-2.6.35-28-generic linux-image-generic
[[email protected]]$ echo ${_constr[2]}
linux-image-generic

и вы можете получить количество элементов, используя ${#_constr[*]}.

[[email protected]]$ echo ${#_constr[*]}
3

Ответ 3

В качестве альтернативы вы можете переместить операторы эха внутри подселочки:

dpkg --list |grep linux-image |grep "ii  " | (
  let i=0
  declare -a arr

  while read line
  do
    arr=(${line})
    let i=i+1
    _constr+="${arr[2]} "
  done
  echo $i
  echo ${_constr}
)

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