Regex 如何在bash中使用数组成员作为搜索或替换模式?

Regex 如何在bash中使用数组成员作为搜索或替换模式?,regex,arrays,bash,scripting,replace,Regex,Arrays,Bash,Scripting,Replace,我有大约一千个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 A

我有大约一千个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的行按预期打印1月1日、2月2日等,但在下一行中使用它们作为搜索或替换模式没有效果,$FILE按原样打印

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

${FILE/Jan/01}

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

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
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

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


此版本避免了特定于bash的代码。我也在debug echo步骤中离开了,最后一部分也被注释掉了。

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


此版本避免了特定于bash的代码。我也留下了调试回音步骤,并将最后一部分注释掉。

我将答案和注释放在一起,并按如下方式解决了问题:

# 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个月名称的模式匹配,并且避免了我问题中的嵌套循环结构。它也不使用任何额外的管道,即使分离器与_不同也可以工作

我把答案和评论放在一起,并按如下方式解决了问题:

# 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个月名称的模式匹配,并且避免了我问题中的嵌套循环结构。它也不使用任何额外的管道,即使分离器与_不同也可以工作

您使用的是什么版本的bash?检查$BASH\u版本。您的脚本可以在运行3.2.481-release的Mac和运行3.2.251-release的Linux上运行。您可以尝试改名为:rename-ns/${match[i]}/${replace[i]}也可以在bash 4.2.450中运行。但这似乎不是最好的方法;我将建议另一个替代方案作为答案;yyyy-mm?@tripleee没错!我这么做的主要原因是为了方便对文件进行排序。我没有在这里提到它,因为它与问题无关。您使用的是什么版本的bash?检查$BASH\u版本。您的脚本可以在运行3.2.481-release的Mac和运行3.2.251-release的Linux上运行。您可以尝试改名为:rename-ns/${match[i]}/${replace[i]}也可以在bash 4.2.450中运行。但这似乎不是最好的方法;我将建议另一个替代方案作为答案;yyyy-mm?@tripleee没错!我这么做的主要原因是为了方便对文件进行排序。我在这里没有提到它,因为它与问题无关。值得指出的是,关联数组是在bash 4.0中添加的。值得指出的是,关联数组是在bash 4.0中添加的。
# 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