Bash:遍历名称中包含模式的变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25765282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:19:52  来源:igfitidea点击:

Bash: loop through variables containing pattern in name

bashvariablesfor-loop

提问by Bjorn

In my script I have an unknown number of variables containing angles which I want to convert to vectors. I made the variable-names such that the angles of each 'parameter' are of the form: {parameter}_angle_{lat/perp} Hence, each parameter has a 'lat' and 'perp' angle variable. So what I want to do is to find all variables containing '_angle_lat', do some calculations on the values of these variables and create a new variable which contains the 'parameter'-name in it. for example:

在我的脚本中,我有一个未知数量的变量,其中包含我想转换为向量的角度。我制作了变量名,使得每个“参数”的角度都采用以下形式: {parameter}_angle_{lat/perp} 因此,每个参数都有一个“lat”和“perp”角度变量。所以我想要做的是找到所有包含“_angle_lat”的变量,对这些变量的值进行一些计算,然后创建一个包含“参数”名称的新变量。例如:

export M0_angle_lat=4
export M1_angle_lat=70
export M1_angle_perp=8
export M0_angle_perp=90

# Now I want to use these values to calculate vectors
for varname in *_angle_lat
do
    # at first iteration it will get for example "varname=M0_angle_lat" in which case
    # I want it to do:
    M0_X=$(( $M0_angle_lat * $M0_angle_perp ))
    # The second iteration in case would then give "varname=M1_angle_lat" in which case
    # I want it to do:
    M1_X=$(( $M1_angle_lat * $M1_angle_perp ))
done

I hope it's clear what my goal is here. Thanks for the help!

我希望很清楚我在这里的目标是什么。谢谢您的帮助!

回答by RedX

What you can do is use envto get a list of all variables and then iterate through them:

您可以做的是使用env获取所有变量的列表,然后遍历它们:

while IFS='=' read -r name value ; do
  if [[ $name == *'_angle_lat'* ]]; then
    echo "$name" ${!name}
    prefix=${name%%_*} # delete longest match from back (everything after first _)
    angle_lat="${prefix}_angle_lat"
    angle_perp="${prefix}_angle_perp"
    result="${prefix}_X"
    declare "${result}=$(( ${!angle_lat} * ${!angle_perp} ))"       
  fi
done < <(env)

回答by chepner

This code requires bash4.3, to use the named references created by declare -n.

此代码需要bash4.3,才能使用由declare -n.

This also requires you to rename your variables slightly.

这还需要您稍微重命名变量。

angle_lat_M0=4
angle_lat_M1=70
angle_perp_M1=8
angle_perp_M0=90

# Now I want to use these values to calculate vectors
for varname in ${!angle_lat*}
do
    # Ref to angle_lat_*
    declare -n lat=$varname
    # Ref to angle_perp_*
    declare -n perp=${varname/_lat_/_perp_}
    # Ref to X_*
    declare -n x=${varname/angle_lat_/X_}

    x=$((lat * perp))
done

echo $X_M0
echo $X_M1

Prior to 4.3, you need some extra tricks to work varname. (Actually, it's not as bad as I thought it would be.)

在 4.3 之前,您需要一些额外的技巧才能工作varname。(实际上,它并没有我想象的那么糟糕。)

angle_lat_M0=4
angle_lat_M1=70
angle_perp_M1=8
angle_perp_M0=90

# Now I want to use these values to calculate vectors
for varname in ${!angle_lat*}
do
    tag=${varname#angle_lat_}  # M0, M1, etc
    lat=${!varname}
    perp_name=angle_perp_$tag
    perp=${!perp_name}
    x=$((lat * perp))

    declare "X_$tag=$x"
done

echo $X_M0
echo $X_M1

Even simpler, and it should work for all versions of bash(possibly excluding some very old versions, but 3.2 at least is supported). It's simpler mainly because it forgoes trying to iterate over a set of similar variable names.

更简单,它应该适用于所有版本bash(可能不包括一些非常旧的版本,但至少支持 3.2)。它更简单,主要是因为它放弃了对一组相似变量名称进行迭代的尝试。

lats=( $M0_angle_lat $M1_angle_lat )
perps=( $M0_angle_perp $M1_angle_lat )
declare -a x

for i in "${!lats[@]}"; do
    x+=(${lats[i]} * ${perps[i]})
done

M0_X=${x[0]}
M1_X=${x[1]}
# or
for i in "${!x[@]}"; do
    declare "M${i}_X"=${x[i]}
done