【发布时间】:2009-10-31 09:09:25
【问题描述】:
如何递归地将xxx-xxx_[a-zA-Z]+_\d+_(\d+)\.jpg 更改为$1.jpg?
【问题讨论】:
如何递归地将xxx-xxx_[a-zA-Z]+_\d+_(\d+)\.jpg 更改为$1.jpg?
【问题讨论】:
#!/bin/bash
find . | while read OLD; do
NEW="`sed -E 's/(.*\/)?xxx-xxx_[a-zA-Z]+_[0-9]+_([0-9]+)\.jpg/\1\2.jpg/' <<< "$OLD"`"
[ "$OLD" != "$NEW" ] && mv "$OLD" "$NEW"
done
对此的一些说明:
将find 的输出连接到while read 循环是一次读取find 输出的一种简洁方式。这很好,因为它会在 find 找到它们时处理文件,而不必先建立整个文件列表,如果你在反引号中使用 `find` 就会发生这种情况。
如果您有大量不相关的文件,那么您可以按照 soulmerge 的回答将 -regex 选项添加到 find,但如果没有,则不需要。
我修改了您的正则表达式以允许在前面使用目录名称。他们将在\1 中被捕获,您要查找的号码将是\2。
sed <<< "$OLD" 和echo "$OLD" | sed 是一样的,只是更花哨一点……
[ "$OLD" != "$NEW" ] && mv 和if [ "$OLD" != "$NEW" ]; then mv; fi 是一样的,只是更高级一点……
编辑:为了兼容性,将\d 更改为[0-9]。我在我的 Mac 上测试了它,它可以工作。以下是我设置的测试目录中发生的情况:
mv ./1/xxx-xxx_ERR_19_02.jpg ./1/02.jpg
mv ./2/xxx-xxx_BLAH_266_14.jpg ./2/14.jpg
mv ./xxx-xxx_ERR_19_01.jpg ./01.jpg
【讨论】:
find 是递归的,所以应该这样!
在SuperUser.com 上查看此问题的各种答案。它正在处理相同的问题(使用正则表达式重命名文件)。 [我花了很长时间才在 StackOverflow 上找到它——因为它不在 SO 上,而是在 SU 上! :( ]
【讨论】:
我正在为您提供可以处理任何文件名的更详细的版本(即使是那些在带有空格污染名称的文件夹中的文件):
# file rename.sh
old="$1"
new="$(dirname "$1")/$(echo "$(basename "$1")"|sed 's/^xxx-xxx_[a-zA-Z]+_[0-9]+_//')"
mv "$old" "$new"
# execute this in the shell:
find . -regex "xxx-xxx_[a-zA-Z]+_[0-9]+_[0-9]+\.jpg$" -exec ./rename.sh "{}" ";"
【讨论】:
find 默认情况下是递归的。如果您希望它不存在,则必须指定选项。
如果你有rename(或prename)命令(它是一个 Perl 脚本,有时 Perl 附带):
find -type d -name dir -exec rename 's/xxx-xxx_[a-zA-Z]+_\d+_(\d+)\.jpg/$1.jpg/' {}/xxx-xxx_[a-zA-Z]*[0-9].jpg \;
【讨论】:
s/.../.../ 是 Perl(和 sed)的替代命令。它在第一个和第二个斜杠之间搜索正则表达式,并将其替换为第二个和第三个斜杠之间的正则表达式。 $1 是对括号中正则表达式部分的反向引用(sed 使用 \1)。
find /path -type f -name "???-???_[a-zA-Z]*_[0-9]*_*.???" | while read FILE
do
f=${FILE%%.???}
number=${f##*_}
extension=${FILE##*.}
path=${FILE%/*}
echo "mv '$FILE' '$path/$number.$extension"
done
【讨论】: