Linux Bash Shell脚本嵌套循环的内部循环不工作
在尝试重命名一组变化为(1-26)、左/右和png/bmp的文件时,我有以下脚本Linux Bash Shell脚本嵌套循环的内部循环不工作,linux,bash,shell,Linux,Bash,Shell,在尝试重命名一组变化为(1-26)、左/右和png/bmp的文件时,我有以下脚本 #!/bin/bash NUMBER_LIST=$(seq -f "%03g" 1 26) EXT_LIST=("png" "bmp") SIDE_LIST=("right" "left") for NUMBER in $NUMBER_LIST do for SIDE in $SIDE_LIST do for EXT in $EXT_LIST do
#!/bin/bash
NUMBER_LIST=$(seq -f "%03g" 1 26)
EXT_LIST=("png" "bmp")
SIDE_LIST=("right" "left")
for NUMBER in $NUMBER_LIST
do
for SIDE in $SIDE_LIST
do
for EXT in $EXT_LIST
do
OLD="${SIDE}_${NUMBER}.${EXT}"
NEW="${NUMBER}_${SIDE}.${EXT}"
mv $OLD $NEW
done
done
done
只有指定为右和bmp的文件才会被重命名。所以
看起来它只是迭代最外层的循环,而不是迭代内部循环(只使用第一个元素)
我在网上找过其他地方,但找不到任何相关的东西
有没有关于什么可能是错的猜测
谢谢,
杰夫你的第一份作业
NUMBER_LIST=$(seq -f "%03g" 1 26)
将从seq
的输出创建的字符串指定给NUMBER\u LIST
。你接下来的两项作业
EXT_LIST=("png" "bmp")
SIDE_LIST=("right" "left")
创建数组。对于数组变量,$EXT\u LIST
相当于${EXT\u LIST[0]}
,也就是说,它只是数组的第一个元素。要迭代数组的所有值,请使用
for EXT in "${EXT_LIST[@]}"
请注意,最外层的循环是有效的,因为您正在迭代存储在
NUMBER\u LIST
中的以空格分隔的字符串。也就是说,如果NUMBER\u LIST
是01123
,则NUMBER
按0、1、2、3的顺序设置。同样的情况也适用于错误的循环尝试。考虑
EXT_LIST=("png bmp" "gif tif")
for EXT in $EXT_LIST; do
EXT\u LIST
将扩展到png bmp
,由于扩展没有被引用,EXT
将被分配到png
,然后bmp
。如果你写错了
for EXT in ${EXT_LIST[@]}; do
然后EXT
将png
,bmp
,gif
,然后tif
作为其值。这同样是错误的
for EXT in "$EXT_LIST"; do
将生成一次迭代,并将EXT
赋值为png-bmp-gif-tif
您的第一次赋值
NUMBER_LIST=$(seq -f "%03g" 1 26)
将从seq
的输出创建的字符串指定给NUMBER\u LIST
。你接下来的两项作业
EXT_LIST=("png" "bmp")
SIDE_LIST=("right" "left")
创建数组。对于数组变量,$EXT\u LIST
相当于${EXT\u LIST[0]}
,也就是说,它只是数组的第一个元素。要迭代数组的所有值,请使用
for EXT in "${EXT_LIST[@]}"
请注意,最外层的循环是有效的,因为您正在迭代存储在
NUMBER\u LIST
中的以空格分隔的字符串。也就是说,如果NUMBER\u LIST
是01123
,则NUMBER
按0、1、2、3的顺序设置。同样的情况也适用于错误的循环尝试。考虑
EXT_LIST=("png bmp" "gif tif")
for EXT in $EXT_LIST; do
EXT\u LIST
将扩展到png bmp
,由于扩展没有被引用,EXT
将被分配到png
,然后bmp
。如果你写错了
for EXT in ${EXT_LIST[@]}; do
然后EXT
将png
,bmp
,gif
,然后tif
作为其值。这同样是错误的
for EXT in "$EXT_LIST"; do
将产生一次迭代,并将
EXT
赋值为png bmp gif tif
甚至更好,因为这里更简单,也不需要数组,因此正在更改变量的值,并保持解引用不变:
EXT_LIST="png bmp"
SIDE_LIST="right left"
更妙的是,因为这里更简单,也不需要数组,所以更改变量的值并保持解引用不变:
EXT_LIST="png bmp"
SIDE_LIST="right left"
另一种避免循环的方法是从正确的文件名开始。 正在为001编写正则表达式。。026也是可能的,但我只在第一次查找时检查数字,然后再检查数字
regex_side="\(left\|right\)"
regex_ext="\(bmp\|png\)"
find . -maxdepth 1 -regextype sed -regex ".*/${regex_side}_[0-9]\{3\}\.${regex_ext}" | while read -r f; do
filename="${f##*/}"
side_number="${filename%.*}"
side="${side_number%_*}"
number="${side_number##*_}"
if [ ${number} -lt 26 ] && [ ${number} -gt 0 ]; then
printf "%s\n" "mv ${f} ${f%/*}/${number}_${side}.${f##*.}"
# When you like the mv statement, delete the # on the next line
# mv "${f}" "${f%/*}/${number}_${side}.${f##*.}"
fi
done
编辑:添加了带有sed
的解决方案
您可以使用sed解决方案避免查找。这会比较慢,因为bash需要为每个文件调用sed。我认为sed解决方案更容易理解:
regex_side="\(left\|right\)"
regex_ext="\(bmp\|png\)"
for file in *; do
# When your shell supports it: newname=$(sed -e "..." <<< "${file}")
newname=$(echo "${file}" |
sed -e "s/^${regex_side}_\([0-9]\{3\}\)\.${regex_ext}$/\2_\1.\3/")
if [ "${file}" != "${newname}" ]; then
number="${newname%%_*}"
if [ ${number} -lt 26 ] && [ ${number} -gt 0 ]; then
printf "%s\n" "mv ${file} ${newname}"
# When you like the mv statement, delete the # on the next line
# mv "${file}" "${newname}"
fi
fi
done
regex\u-side=“\(左\;右\)”
regex|u ext=“\(bmp\| png\)”
以*存档;做
#当shell支持它时:newname=$(sed-e“…”另一种避免循环的方法是从正确的文件名开始。
也可以为001..026编写正则表达式,但我只在第一次查找时检查数字,然后检查数字
regex_side="\(left\|right\)"
regex_ext="\(bmp\|png\)"
find . -maxdepth 1 -regextype sed -regex ".*/${regex_side}_[0-9]\{3\}\.${regex_ext}" | while read -r f; do
filename="${f##*/}"
side_number="${filename%.*}"
side="${side_number%_*}"
number="${side_number##*_}"
if [ ${number} -lt 26 ] && [ ${number} -gt 0 ]; then
printf "%s\n" "mv ${f} ${f%/*}/${number}_${side}.${f##*.}"
# When you like the mv statement, delete the # on the next line
# mv "${f}" "${f%/*}/${number}_${side}.${f##*.}"
fi
done
编辑:添加了带有sed
的解决方案
您可以避免使用sed解决方案查找。这样会比较慢,因为bash需要为每个文件调用sed。我认为sed解决方案更容易理解:
regex_side="\(left\|right\)"
regex_ext="\(bmp\|png\)"
for file in *; do
# When your shell supports it: newname=$(sed -e "..." <<< "${file}")
newname=$(echo "${file}" |
sed -e "s/^${regex_side}_\([0-9]\{3\}\)\.${regex_ext}$/\2_\1.\3/")
if [ "${file}" != "${newname}" ]; then
number="${newname%%_*}"
if [ ${number} -lt 26 ] && [ ${number} -gt 0 ]; then
printf "%s\n" "mv ${file} ${newname}"
# When you like the mv statement, delete the # on the next line
# mv "${file}" "${newname}"
fi
fi
done
regex\u-side=“\(左\;右\)”
regex|u ext=“\(bmp\| png\)”
要在*中归档;请执行以下操作
#当您的shell支持它时:newname=$(sed-e“…”您正在创建数组(除了$NUMBER\u LIST
),因此您必须将循环基于数组,例如“${SIDE\u LIST[@]”中的for SIDE
。此外,我建议不要使用所有大写变量名。像标量一样引用数组变量-例如,$SIDE_LIST
-隐式返回索引为0
的数组元素,因此您只能循环1个值。我同意@mklement0在所有帐户上的说法,应该可以解决您的问题。@mklement0有效s、 我不确定我是否理解这个案例是如何将其定义为标量的。你能详细说明一下吗?数组声明(即$SIDE_列表)需要小写吗?元素声明(即SIDE)需要小写吗?或者元素引用(即$SIDE)?最好的做法是为shell保留大写变量,为用户保留小写。@WoodMath:正如miken32的评论所暗示的,大小写问题是不相关的。它是如何引用数组变量来确定是否返回标量:$SIDE_LIST
是标量引用,而“${SIDE_LIST[@]}”
返回整个数组。您正在创建数组(除了$NUMBER\u LIST
),因此您必须将循环基于数组,例如“${SIDE\u LIST[@]”中的for SIDE
。此外,我建议不要使用所有大写变量名。像标量一样引用数组变量-例如,$SIDE_LIST
-隐式返回索引为0
的数组元素,因此您只能循环1个值。我同意@mklement0在所有帐户上的说法,应该可以解决您的问题。@mklement0有效s、 我不确定我是否理解这个案例是如何将它定义为标量的。你能详细说明一下吗?你知道吗