Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux Bash Shell脚本嵌套循环的内部循环不工作_Linux_Bash_Shell - Fatal编程技术网

Linux Bash Shell脚本嵌套循环的内部循环不工作

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

在尝试重命名一组变化为(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  
            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、 我不确定我是否理解这个案例是如何将它定义为标量的。你能详细说明一下吗?你知道吗