Невозможно добавить элемент в массив в bash

У меня есть следующая проблема. Предположим, что [email protected] содержит только действительные файлы. Переменная file содержит имя текущего файла (в настоящее время файл "on"). Затем переменная element содержит данные в формате file:function.

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

Я написал два способа, которые я пытаюсь вставить элемент в массив, но не работает. Можете ли вы сказать мне, что я делаю неправильно, пожалуйста?

Я использую Linux Mint 16.

#!/bin/bash

nm [email protected] | while read line
do
  pattern="`echo \"$line\" | sed -n \"s/^\(.*\):$/\1/p\"`"
  if [ -n "$pattern" ]; then
    file="$pattern"  
  fi
  element="`echo \"$line\" | sed -n \"s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p\"`"
  if [ -n "$element" ]; then
    array+=("$element")
    #array[$[${#array[@]}+1]]="$element"
    echo element - "$element"
  fi
done

for j in "${array[@]}"
do
  echo "$j"
done

Ответ 1

Ваша проблема заключается в том, что цикл while выполняется в подоболочке, потому что это вторая команда в конвейере, поэтому любые изменения, сделанные в этом цикле, недоступны после выхода цикла.

У вас есть несколько вариантов. Я часто использую { и } для группирование команд:

nm "[email protected]" |
{
while read line
do
    …
done
for j in "${array[@]}"
do
    echo "$j"
done
}

В bash вы также можете использовать замещение процесса:

while read line
do
    …
done < <(nm "[email protected]")

Кроме того, лучше использовать $(…) вместо обратных кавычек `…` (а не только потому, что это тяжелая работа, возвращающая цитаты в текст уценки!).

Ваша строка:

element="`echo \"$line\" | sed -n \"s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p\"`"

можно написать:

element="$(echo "$line" | sed -n "s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p")"

или даже:

element=$(echo "$line" | sed -n "s/^U \([0-9a-zA-Z_]*\).*/$file:\1/p")

Это действительно помогает, когда вы в них нуждаетесь. Например, чтобы найти каталог lib рядом с тем, где gcc найден:

ls -l $(dirname $(dirname $(which gcc)))/lib

против

ls -l `dirname \`dirname \\\`which gcc\\\`\``/lib

Я знаю, что мне легче!