这实际上不是一个问题,我自己解决了这个问题。但是我想在这里发布我的解决方案,以便在同样的情况下节省其他人的时间和精力。
所以我遇到了必须重命名(+3000)匹配特定模式的情况。在我的例子中,文件是来自syncthing的自动备份,因此文件将重命名为:
foo.bar -> foo~20150221-1330.bar
答案 0 :(得分:3)
通过论坛和手册页进行了大量搜索后,我创建了以下单行程序,用linux中的find,sed
,xargs
和mv
命令恢复原始文件名:
find . -type f | sed -e 'p;s/\(.*\)~20[0-9]\{6\}-[0-9]\{6\}\(.*\)/\1\2/' | xargs -n2 -d'\n' mv
如果您愿意,可以使用自己的模式替换sed
- 部分。顺便说一下,这个命令可以处理空格(感谢-d'\n'
中的xargs
标志),但不是新行。
我希望你们中的一些人觉得这个命令很有用。
好的,我将提供有关每个命令的更多信息:
find
:提供当前目录中的所有常规文件(不是目录) sed
:p
将打印stdin中的每一行,s/regex/regex/
将打印相同的行,但会替换。所以你得到每个文件后跟固定文件名:
./foo/bar~20150221-172703.txt
./foo/bar.txt`
xargs
:-n2
将占用两行并将其作为参数发送至mv
,-d' \ n'将解决文件夹名称中的空格问题(分隔符设置为换行符而不是空格)答案 1 :(得分:0)
您的答案很好,但是如果您还想要解决也包含换行符的文件名,如果您不想使用sed
,并且您想要确保只有的文件与此模式匹配的基本名称会被考虑在内(您的方法失败,例如,使用dir~20150221-172703/file
,并且您的方法会使mv
对file
和{{1}抱怨很多当文件名与你的模式不匹配时,它是同一个文件)你需要稍微不同地进行。
一种可能性,如果您的file
支持find
选项(GNU -print0
会这样做):让find
吐出所有文件名,并使用find
循环,其中Bash(不是while
)将执行替换。像这样:
sed
您还可以确保find . -type f -print0 | while IFS= read -r -d '' file; do
dirname=${file%/*}
basename=${file##*/}
# Perform the substitution only on basename
# Since you like regex, you can use them
if [[ $basename =~ ^(.*)~20[0-9]{6}-[0-9]{6}(.*)$ ]]; then
new_basename=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
echo mv "$dirname/$basename" "$dirname/$new_basename"
fi
done
仅使用find
过滤器(不是POSIX,但GNU -regex
支持)来吐出匹配文件:
find
不确定这完全回答了你的问题,但至少它解决了你的方法存在的缺陷。
如果没有GNU的好东西,那么拥有健壮和干净的东西就更难了......
答案 2 :(得分:0)
您可以使用rnm:
rnm -rs '/(.*)~20[0-9]{6}-[0-9]{6}(.*)/\1\2/' -fo -dp -1 *
-fo
:仅文件模式-dp
:目录深度(-1表示无限深度,即所有子目录)。您可以完全使用自己的正则表达式模式,在这种情况下,您必须将正则表达式模式更改为基本模式(BRE):
rnm --regex basic -rs '/\(.*\)~20[0-9]\{6\}-[0-9]\{6\}\(.*\)/\1\2/' -fo -dp -1 *
注意:
/
)。