【问题标题】:Bash build array in while loop (does not persist)? [duplicate]Bash 在 while 循环中构建数组(不持久)? [复制]
【发布时间】:2018-04-23 06:42:12
【问题描述】:

考虑这个例子,比如说test.sh

cat > test.txt <<'EOF'
test 1
test 2
test 3
EOF

declare -a myarr
declare -p myarr  # "declare: myarr: not found"
myarr=()
declare -p myarr  # "declare -a myarr='()'"
#for (( i=1; i<=3; i++ )); do # ok
sed -n 's!test!TEST!p' test.txt | while read i; do # not preserved ?!
  myarr=("${myarr[@]}" "pass $i")
  declare -p myarr
done
declare -p myarr  # "declare -a myarr='()'" ?!

如果我取消注释for ((... 行,并注释sed -n ... 行,那么bash test.sh 的输出与预期一致:

test.sh: line 8: declare: myarr: not found
declare -a myarr='()'
declare -a myarr='([0]="pass 1")'
declare -a myarr='([0]="pass 1" [1]="pass 2")'
declare -a myarr='([0]="pass 1" [1]="pass 2" [2]="pass 3")'
declare -a myarr='([0]="pass 1" [1]="pass 2" [2]="pass 3")'

但是,如果我按照发布的方式运行脚本,则 myarr 会在 while 循环中构建,但一旦在外部,它就是空的:

test.sh: line 8: declare: myarr: not found
declare -a myarr='()'
declare -a myarr='([0]="pass TEST 1")'
declare -a myarr='([0]="pass TEST 1" [1]="pass TEST 2")'
declare -a myarr='([0]="pass TEST 1" [1]="pass TEST 2" [2]="pass TEST 3")'
declare -a myarr='()'

那么,为什么myarr 在这种情况下(在while 循环之后)是空的 - 我如何让它保持其价值?

【问题讨论】:

标签: arrays bash loops


【解决方案1】:

问题在于,由于使用了管道,您正在分叉一个子外壳并在子外壳内的数组中填充条目。一旦你的循环结束,子shell就会终止,所有的变化都会在那里丢失。

您可以使用进程替换来避免这种情况:

myarr=()

while IFS= read  -r line; do
   myarr+=("pass $line")
done < <(sed -n 's!test!TEST!p' test.txt)

# examine the result
declare -p myarr

输出:

declare -a myarr=([0]="pass TEST 1" [1]="pass TEST 2" [2]="pass TEST 3")

【讨论】:

  • 非常感谢@anubhava -> 这确实是问题所在!干杯!
  • 我更喜欢使用其他形式,例如exec {fd}&lt; &lt;(sed ...); while read -r -u $fd line; do ...; done; exec {fd}&lt;&amp;-,因为它可以防止在循环中意外消耗相同的源,但这是正确的做法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-06
  • 1970-01-01
  • 2014-08-16
  • 2015-11-25
  • 2023-04-01
  • 1970-01-01
  • 2014-08-06
相关资源
最近更新 更多