for 循环 Linux 中 shell 命令中的两个变量

Two variable in shell command in for loop Linux

提问人:mashimena 提问时间:8/21/2023 最后编辑:mashimena 更新时间:8/23/2023 访问量:89

问:

我正在尝试根据表格将两个变量放入shell脚本中进行循环。下表如下:

红色文件 之:
CLA164型 16,19,65,77
CLA166型 23,36,93
CLA179型 26,43
CLA180型 22,36,40

我目前使用的代码:

for i in 16 19 65 77; do
  sh cacul.aft.sh --aftfile /path/folder/aft${i} --red-file cla164.input --out /path/folder/re/cla164.aft${i}
done

for i in 23 36 93; do
  sh cacul.aft.sh --aftfile /path/folder/aft${i} --red-file cla166.input --out /path/folder/re/cla166.aft${i}
done

for i in 26 43; do
  sh cacul.aft.sh --aftfile /path/folder/aft${i} --red-file cla179.input --out /path/folder/re/cla179.aft${i}
done

for i in 22 36 40; do
  sh cacul.aft.sh --aftfile /path/folder/aft${i} --red-file cla180.input --out /path/folder/re/cla180.aft${i}
done

但是我想在shell命令中一次将两个变量放入循环中。我已经尝试了如下代码:

for i in 16 19 65 77 23 36 93 26 43 22 36 40; do
  sh cacul.aft.sh --aftfile /path/folder/aft${i} --red-file cla${p}.input --out /path/folder/re/cla${p}.aft${i}
done

我无法弄清楚如何假设循环结构中的第二个变量。我怎样才能在bash中实现这一点?我还尝试假设 2 个 BASH 数组,如下所示:${p}

var1=("164" "164" "164" "164" "166" "166" "166" "179" "179" "180" "180" "180")
var2=("16" "19" "65" "77" "23" "36" "93" "26" "43" "22" "36" "40")

for ((i=0; i<${#var1[@]}; i++)); do
  sh cacul.aft.sh --aftfile /path/folder/aft${var2[$i]} --red-file cla${var1[$i]}.input --out /path/folder/re/cla${var1[$i]}.aft${var2[$i]}
done

我知道我的for循环结构有问题。我怎样才能实现这个目标。谢谢。

bash 循环

评论

0赞 user1934428 8/21/2023
带有数组的版本在我看来是合理的(数组定义中不需要引号)。为了安全起见(魔鬼从不睡觉),我会在之前检查两个阵列的大小是否相同。我也很惊讶您在指定 .也许是遗漏?aft-aftfile
0赞 Weijun Zhou 8/21/2023
相关新闻: stackoverflow.com/q/6145540/3966456
0赞 mashimena 8/21/2023
@user1934428,是的,这是我的mistacke。代码让我头晕目眩。感谢您的提醒。
0赞 user1934428 8/21/2023
顺便说一句,另一种方法是遍历单个对数组(使用合适的分隔符),即 ( ....)。当然,在调用 shell 脚本时,您必须将这对拆分为它的组成,但它的优点是我们可以很容易地看到,哪个值与哪个其他值配对,所以最终,它可能更易于维护。164,16164,19
1赞 user1934428 8/21/2023
正如我所描述的: .这为您提供了对字符串 164,19 的每次迭代,您可以从中提取 164 和 19for pair in 164,16 164,19 ....pair

答:

1赞 Freeman 8/21/2023 #1

为什么不使用带有共享索引变量的循环呢?在我的场景中,我将使用变量遍历数组,并在循环中,变量将保存 的值,并且变量将重新赋值为 ,因此通过这个,您可以根据需要方便地在循环中使用这两个变量!!foripvar1[i]ivar2[i]

像这样的东西:

var1=("164" "164" "164" "164" "166" "166" "166" "179" "179" "180" "180" "180")
var2=("16" "19" "65" "77" "23" "36" "93" "26" "43" "22" "36" "40")

for ((i = 0; i < ${#var1[@]}; i++)); do
  p="${var1[i]}"
  i="${var2[i]}"
  sh cacul.aft.sh --aftfile "/path/folder/aft${i}" --red-file "cla${p}.input" --out "/path/folder/re/cla${p}.aft${i}"
done

评论

1赞 Ivan 8/22/2023
你可以只遍历数组的索引for i in ${!var1[@]}; { ...; }
1赞 Ivan 8/21/2023 #2

尝试使用数组,将变量转换为数组:

# "164" "164" "164" "164" "166" "166" "166" "179" "179" "180" "180" "180"
# "16"  "19"  "65"  "77"  "23"  "36"  "93"  "26"  "43"  "22"  "36"  "40"

arr[16]=164
arr[19]=164
arr[65]=164
arr[77]=164
arr[23]=166
arr[36]=166
arr[93]=166
arr[26]=179
arr[43]=179
arr[22]=180
arr[36]=180
arr[40]=180

遍历数组中的索引:

for i in ${!arr[@]}; {
    p=${arr[i]}
    sh cacul.aft.sh --aftfile /path/folder/aft${i} --red-file cla${p}.input --out /path/folder/re/cla${p}.aft${i}
}

但是有局限性,如果某些索引被配音,一些数据可能会丢失,正如评论中指出的那样。这是使用数组和名称匹配前缀的不同方法。

cla164=(16 19 65 77)
cla166=(23 36 93)
...
for i in ${!cla*}; do
    echo $i
    a="$i[@]"
    for j in "${!a}"; {
        echo $j
    }
done

结果:

cla164
16
19
65
77
cla166
23
36
93

评论

1赞 mashimena 8/23/2023
嗨,我尝试了代码,如果有重复的值。会错过 asuume 先的数组。比如:,会错过arr[16]=164,我怎样才能更好地解决它。aftarr[16]=164 , arr[16]=168
1赞 Ivan 8/23/2023
@mashimena是的,这是这种方法的局限性,用另一个例子更新了我的答案。
3赞 user1934428 8/21/2023 #3

使用两个索引数组的解决方案很好。这里有一个替代的想法:

为了更好地在代码中记录哪些项属于一起,请将相应的项成对:

for p in 16,164 19,164 40,180 # aft,red pairs
do
  sh cacul.aft.sh --aftfile /path/folder/aft${p#*,} --red-file "cla${p%,*}.input" --out "/path/folder/re/cla${p%,*}.aft${p#*,}"
done

评论

0赞 mashimena 8/23/2023
嗨,我不清楚在您的代码中,为什么它们可以正确指示值?#%
0赞 user1934428 8/23/2023
@mashimena:请看一下 bash 手册页,标题为“参数扩展”的部分。它解释了语法和许多其他有用的东西。${parameter#word}${parameter%word}
2赞 Fravadona 8/21/2023 #4

一种明显不同的方法,使用伪 2D 数组:

#!/bin/bash

config=(
    [164]=6,19,65,77
    [166]=23,36,93
    [179]=26,43
    [180]=22,36,40
)

for red in "${!config[@]}"                   #=> loop 164 166 179 180
do
    IFS=',' read -a arr <<< "${config[red]}" #=> split "X,Y,Z" into ( X Y Z )

    for aft in "${arr[@]}"                   #=> loop X Y Z
    do
        sh cacul.aft.sh --aftfile /path/folder/"$aft" \
                        --red-file cla"$red".input \
                        --out /path/folder/re/cla"$red".aft"$aft"
    done
done