1

我有大约一千个 PDF 文件,其名称如Foo_Jan_2013.pdf, Bar_Feb_2012.pdf, Foo_Mar_2013.pdf, Bar_Mar_2013.pdf. 我想重命名这些文件,用数字替换月份名称,例如Foo_01_2013.pdf, Bar_02_2012.pdf, Foo_03_2013.pdf, Bar_03_2013.pdf

我尝试的一种方法是定义两个数组(一个用于匹配模式,另一个用于替换模式),然后在搜索替换中使用相应的数组成员,如下所示:

match=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
replace=(01 02 03 04 05 06 07 08 09 10 11 12);

for FILE in *.pdf;
do 
    for i in {0..11};    
    do
        echo ${match[i]} ${replace[i]};  # Note, see below
        echo ${FILE/${match[i]}/${replace[i]}};
    done
done

标记为Note的行按预期打印Jan 01,Feb 02等,但在下一行中将它们用作搜索或替换模式无效,并按$FILE原样打印。

我还确认了以下两项工作:

${FILE/Jan/01};

foo=Jan;
bar=01;
${FILE/$foo/$bar};

是否可以像我上面尝试的那样使用数组成员作为模式?如果是这样,正确的语法是什么?如果没有,我还有什么其他选择来解决这个问题?

4

3 回答 3

2

BASH 支持非常适合您的用例的关联数组:

# Initialize the associative array
declare -A months

# Fill in the array with the month string as the key and the zero-padded month number as the value
num=0
for m in Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec; do
  ((num++))
  months[$m]=$(printf '%02d' $num)
done

# Test your examples
for file in Foo_Jan_2013.pdf Bar_Feb_2012.pdf Foo_Mar_2013.pdf Bar_Mar_2013.pdf; do
  month=$(cut -d_ -f2 <<<"$file")
  new_name="${file/$month/${months[$month]}}"
  echo "$file -> $new_name"
done

输出:

Foo_Jan_2013.pdf -> Foo_01_2013.pdf
Bar_Feb_2012.pdf -> Bar_02_2012.pdf
Foo_Mar_2013.pdf -> Foo_03_2013.pdf
Bar_Mar_2013.pdf -> Bar_03_2013.pdf
于 2013-10-05T17:23:37.053 回答
2

对于这种情况,我最喜欢的技巧是使用 (eg) 生成一系列命令sed

num=0
subst=
for month in Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec; do
    num=$(($num + 1))
    case $num in ?) num2=0$num;; *) num2=$num; esac
    subst="$subst -e 's/\(.*\)_${month}_\(.*\)/mv & \1_${num2}_\2/'"
done
# echo "sed $subst" # debug
# echo Foo_Jan_2013.pdf | eval sed $subst # debug
ls *.pdf | eval sed $subst # debug
# ls *.pdf | eval sed $subst | sh # once it all works

(此版本避免了特定于 bash 的代码)。我也离开了 debug-echo 步骤,并把最后一部分注释掉了。

于 2013-10-05T20:50:14.093 回答
1

我将iscfrctorek的答案和devnull的评论放在一起,并解决了如下问题:

# Initialize an associative array with (month name, number) pairs
declare -A map=([Jan]=01 [Feb]=02 [Mar]=03 [Apr]=04 [May]=05 [Jun]=06 
[Jul]=07 [Aug]=08 [Sep]=09 [Oct]=10 [Nov]=11 [Dec]=12);

# For each month name, use 'rename' command on filenames having the month name
for m in ${!map[@]};
do
    eval rename \'s/$m/${map[$m]}/\' *$m*.pdf
done

使用这种方法,每个文件名仅与它包含的模式匹配不是所有 12 个月的名称),并且避免了我的问题中的嵌套循环结构。它也不使用任何额外的管道,即使“分隔符”不同于_.

于 2013-10-06T05:56:05.180 回答