【问题标题】:propagating a variable in a for loop bash在 for 循环 bash 中传播变量
【发布时间】:2014-10-29 23:01:34
【问题描述】:

我有 15 个路径存储在一个数组变量中,文件名也存储为另一个数组变量,我想将每个路径绑定到其对应的文件。我正在寻找将每个路径元素与其相应文件绑定的东西,如下所示:

ar1=([1]="path1" [2]="path2")
ar2=([1]="file1" [2]="file2")

我需要:

ar3=([1]="path1/file1" [2]="path2/file2")

我通过一个简单的 for 循环成功管理:

for i in {1..2}; do
  ar3=("${ar1[$i]}""/""${ar1[$i]}"".txt")
done

但我需要变量 ar3 用于脚本的其他部分,并且我不能在 for 循环子 shell 之外使用它。

非常感谢, 伙计

【问题讨论】:

  • for 循环不引入子外壳上下文。你不需要像那样插入和退出引号。你也不需要在[$i] 中使用$i,数组索引是一个表达式上下文,所以[i] 就足够了。
  • @JohnKugelman 因为我实际上并不知道他的问题 是什么,而我的回答只是对未提出问题中固有的假设的否定。如果问题实际上是“这是否可行,因为我担心子外壳会妨碍”,那么这很可能是答案,在这种情况下,答案是“不,它不会”。
  • 你能写出你将如何做循环吗?当我在循环之后放置 echo ${ar3[*]} 时,它不会打印出来。
  • @Guy,for 循环本身不会阻止它的工作,所以你正在代码中的其他地方做一些事情(比如隐式创建一个子shell),这会破坏它。因为您没有向我们展示任何其他代码,所以我们无法告诉您在哪里/如何做错了。
  • 顺便说一句,echo ${ar3[*]} 通常是不好的做法——你无法用这种用法区分ar3=( "foo bar" baz ) 和ar3=( foo "bar baz" ),而ar3=( "*" ) 会真的 i> 搞砸了(打印当前目录中的文件列表,而不是 *)。

标签: arrays bash variables for-loop subshell


【解决方案1】:

您可以测试它是否有效,并将结果传播到循环之外,如下所示:

dirnames=( path1 path2 )
basenames=( file1 file2 )
paths=( )
for idx in "${!dirnames[@]}"; do
  [[ ${basenames[$idx]} ]] || continue
  paths[$idx]=${dirnames[$idx]}/${basenames[$idx]}.txt
done
printf '%q\n' "${paths[@]}"

您会看到这确实正确打印了path1/file1 和path2/file2。

这里有一些改进——但它所做的唯一关键的事情是在循环之前初始化数组。。不这样做意味着只有最后一个被迭代的项目会被存储,因为你会在每次迭代时用一个新的(单个)项目覆盖数组。

如果您之前看到返回零项而不是一项的行为,您很可能在问题中未给出的部分代码中创建了一个子shell。有关此常见问题的讨论,请参阅 BashFAQ #24。

【讨论】:

  • 尽管代码非常好(也许除了缺少的“.txt”后缀),但说它与问题中的代码没有什么显着不同是不正确的。首先,它将basename 附加到dirname 而不是将dirname 附加到dirname。其次,它在每次循环时都在路径数组中设置适当的索引,而不是每次循环时都将 ar3 数组重新初始化为单元素数组。
  • @pjh, ...呵呵——一些优点;我显然没有仔细阅读原文。好吧,我很高兴提供一个如何正确执行此操作的示例(并在扩展程序中进行编辑)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-02
  • 1970-01-01
  • 2014-10-05
  • 2020-04-21
  • 2016-10-30
  • 2020-09-12
  • 2022-01-04
相关资源
最近更新 更多