问题:我无法在while
循环中更新数组。插图(不实际问题):
declare -A wordcounts
wordcounts["sentinel"]=1000
ls *.txt | while read f; do
# assume that that loop runs multiple times
wordcounts[$f]=$(wc -w $f)
echo ${wordcounts[$f]} # this prints actual data
done
echo ${!wordcounts[@]} # only prints 'sentinel'
这不起作用,因为管道在子shell中运行后循环。循环对变量wordcounts
所做的所有更改仅在循环内可见。
说export wordcounts
没有帮助。
唉,我似乎需要管道和while read
部分,所以使用for
重写上面代码的方法并不是我想要的。< / p>
是否有合法的方法来更新循环或子shell中的关联数组表单?
答案 0 :(得分:7)
由于您正在阅读复杂的命令管道,因此可以使用以下命令:
while read f; do
# Do stuff
done < <(my | complex | command | pipe)
语法<(command)
在子shell中运行命令并将其stdout作为临时文件打开。您可以在任何通常在命令中使用文件的地方使用它。
此外,您还可以使用语法>(command)
将stdin作为文件打开。
答案 1 :(得分:2)
是否有合法的方法来更新a中的关联数组表单 循环,或一般的子shell?
你可以通过说:
来避免子shellwhile read f; do
...
done < *.txt
那就是说,示例代码有问题。循环将逐行读取文件,所以说
wordcounts[$f]=$(wc -w $f)
真的没有多大意义。你可能想说:
wordcounts[$f]=$(wc -w <<< $f)
编辑:
唉,我好像需要管道......
引用manual:
管道中的每个命令都在其自己的子shell中执行(参见Command Execution Environment)。
答案 2 :(得分:2)
如果您使用的是bash
4.2,则可以设置lastpipe
shell选项以允许while循环(作为管道中的 last 元素)在当前shell而不是子shell。
一个简单的演示:
$ echo foo | read word
$ echo $word
$ set +m # Only needed in an interactive shell to disable job control
$ shopt -s lastpipe
$ echo foo | read word
$ echo $word
foo
答案 3 :(得分:0)
为什么不必要地使用ls
。
以下工作正常:
declare -a wordcounts
for f in *.txt; do
wordcounts+=$(wc -w $f)
done
echo ${wordcounts[@]}
答案 4 :(得分:0)
我认为最好的解决方案是Cookyt的解决方案:
while read f; do
# Do stuff
done < <(my | complex | command | pipe)
对我来说,这是行不通的,因为在我的环境中我没有安装/proc
,因为<(cmd)
构造需要/dev/fd/XXX
并且/dev/fd
是指向/proc/self/fd
。在这种情况下,chepner的解决方案起作用:
shopt -s lastpipe
my | complex | command | pipe | while read f; do
# Do stuff
done
如果您还没有bash,那么还有第三种解决方案可用于POSIX shell(因此也适用于bash):
set -- $(my | complex | command | pipe)
while [ -n "$1" ]; do
f="$1"
shift
# Do stuff
done