Bash Shell脚本嵌套循环的内部循环不起作用

时间:2016-02-05 19:25:51

标签: 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  
            OLD="${SIDE}_${NUMBER}.${EXT}"
            NEW="${NUMBER}_${SIDE}.${EXT}"
            mv $OLD $NEW

        done
    done
done

仅重命名指定为正确 bmp 的文件。所以 看起来它只是遍历最外层循环,而不是遍历内部循环(只使用第一个元素)。

我已经在网上寻找过其他地方,但我找不到任何相关内容。

有什么可能出错的猜测?

谢谢, 杰夫

3 个答案:

答案 0 :(得分:4)

您的第一个作业

NUMBER_LIST=$(seq -f "%03g" 1 26)

将从seq的输出创建的字符串分配给NUMBER_LIST。你接下来的两个任务

EXT_LIST=("png" "bmp")
SIDE_LIST=("right" "left")

创建数组。对于数组变量,$EXT_LIST等同于${EXT_LIST[0]},也就是说,它只是数组的第一个元素。要迭代数组的所有值,请使用

for EXT in "${EXT_LIST[@]}"

请注意,您的最外层循环有效,因为您正在迭代NUMBER_LIST中存储的以空格分隔的字符串。也就是说,如果NUMBER_LIST0 1 2 3,则NUMBER设置为0,1,2,然后3.同样适用于您在循环中的错误尝试。考虑

EXT_LIST=("png bmp" "gif tif")
for EXT in $EXT_LIST; do

EXT_LIST会扩展为png bmp,由于未引用扩展,EXT将被分配png,然后bmp。如果你写错了

for EXT in ${EXT_LIST[@]}; do

然后EXTpngbmpgif,然后tif作为其值。

同样不正确
for EXT in "$EXT_LIST"; do

将生成一次迭代,EXT分配值png bmp gif tif

答案 1 :(得分:0)

更好,因为更简单,因为这里不需要数组,正在改变vars的值并保留dereferences:

EXT_LIST="png bmp"
SIDE_LIST="right left"

答案 2 :(得分:0)

另一种避免循环的方法是从正确的文件名开始。 也可以为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