无法在Bash中向数组添加元素

11

我有以下问题。假设$@只包含有效文件。变量file包含当前文件的名称(我当前正在使用的文件)。然后变量elementfile:function的格式包含数据。

现在,当变量element不为空时,它应该被放入数组中。这就是问题所在。如果我输出element,它包含我想要的内容,但它没有存储在数组中,因此循环不会打印任何东西。

我已经尝试了两种方式来将element插入数组,但都无法成功。你能告诉我,我做错了什么吗?

我正在使用Linux Mint 16。

#!/bin/bash

nm $@ | 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
始终使用$(...)而不是反引号。 - Jonathan Leffler
有一些选项可以在每行上打印文件名(通常是-r-R,如果我没记错的话)。这将节省您大部分正在进行的操作工作。 - Jonathan Leffler
使用set -vx(或简化输出)的shell跟踪调试功能。您将看到变量如何被评估,然后通常很容易修复。此外,加入90年代,停止使用反引号进行命令替换。var = $(cmd_produces_output)不是100%可移植的,但更容易阅读和嵌套。最后,在sed命令中仅在需要cmd内部的变量扩展时使用双引号。通常使用单引号,然后避免必须转义它们。祝你好运。 - shellter
3
无论如何,你正在子shell中设定array的值,所以对于接下来的for循环而言,它是未定义的。 - chepner
是的,我知道一些选项。实际上,我使用了-o选项,就像你说的那样,在每行上打印文件名。但是我发现禁止使用任何选项来进行nm操作。 很抱歉,我不明白$(...)的意思。你的意思是我应该将第5行替换为pattern=$(echo "$line"| ...)吗?第9行也是同样的情况。 - user1967718
nm 的输出格式和选项因系统而异。我在我的答案中添加了关于 $(…) 和反引号的解释。请注意,在评论中有效的 MarkDown 在答案中无效(`…` 是与答案中有效的相同字符序列;但在这里不起作用)。 - Jonathan Leffler
1个回答

21
你的问题在于 while 循环运行在子 shell 中,因为它是管道中的第二个命令,所以在循环退出后对其所做的任何更改都不可用。
你有几个选项。我经常使用 {} 进行 命令分组
nm "$@" |
{
while read line
dodone
for j in "${array[@]}"
do
    echo "$j"
done
}

在 bash 中,你也可以使用 进程替换
while read line
do
    …
done < <(nm "$@")

另外,最好使用$(...)代替反引号`...`(不仅因为在Markdown文本中输入反引号很麻烦!)。
你的代码行:
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")

当需要嵌套时,它确实很有帮助。例如,要在找到gcc的位置旁边列出lib目录:

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

对比

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

我知道哪个更容易!

1
哦,非常感谢,我没有意识到子shell。实际上这是我的第一个脚本。所以现在我会知道了。再次感谢你。 - user1967718

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接