在尝试使用(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 的文件。所以 看起来它只是遍历最外层循环,而不是遍历内部循环(只使用第一个元素)。
我已经在网上寻找过其他地方,但我找不到任何相关内容。
有什么可能出错的猜测?
谢谢, 杰夫
答案 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_LIST
为0 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
然后EXT
将png
,bmp
,gif
,然后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