在以下当前文件夹下,我们有文件示例
lok.log.1
df.log.6
weq.log.90
vr.log.11
vs.aw.frsd.log.3
我们想将文件扩展名增加 1
所以预期的输出如下
lok.log.2
df.log.7
weq.log.91
vr.log.12
vs.aw.frsd.log.4
请建议如何使用查找和正则表达式重命名文件
- 这个概念应该是所有具有“.log”的文件将被重命名为+1
答案1
和zsh
:
autoload zmv # best in ~/.zshrc
zmv -n -f '(*.log.)(<->)(#qnOn)' '$1$(($2+1))'
-n
(如果对结果满意则删除)
<->
匹配任何十进制数(#qnOn)
n
: glob 限定符此处按名称 () 以相反顺序按数字 (On
)对文件列表进行排序,因此file.log.2
重命名为file.log.3
beforefile.log.1
重命名为file.log.2
..
如果您只想重命名,请添加常规的文件(但如果您还想重命名隐藏文件,您可能需要添加一个-o-nT
假设 GNU 的选项mv
) 。D
-f
当文件被重命名为现有文件时,禁用会取消该命令的保护措施,这会妨碍我们上面的示例file.log.1
。file.log.2
它仍然会防范两者foo.log.1
并被foo.log.01
重命名为foo.log.2
.
递归地:
zmv -n -f '(**/)(*.log.)(<->)(#qnOn)' '$1$2$(($3+1))'
来自bash
或sh
或ksh
:
zsh << 'EOF'
autoload zmv
zmv -n -f '(*.log.)(<->)(#qnOn)' '$1$(($2+1))'
EOF
无论bash
是否使用 using zsh
,如果您有 GNUls
和 GNU mv
,并且文件列表不是太大,您可以执行以下操作:
shopt -s failglob
shopt -s extglob
export LC_ALL=C
eval "files=($(
ls --quoting-style=shell-always -rvd -- *.log.+([[:digit:]])))"
for f in "${files[@]}"; do
echo mv -nT -- "$f" "${f%.*}.$((10#${f##*.} + 1))"
done
(满意后移除echo
)。
递归地,使用 GNU bash
、 GNU find
、 GNUmv
和 GNU sort
,仅适用于常规文件:
export LC_ALL=C
while IFS= read -rd '' -u3 file; do
echo mv -nT "$file" "${file%.*}.$((10#${file##*.} + 1))"
done 3< <(
find . -name '.?*' -prune -o -regex '.*\.log\.[0-9]+' -type f -print0 |
sort -rzV)
mv -n
是一个 GNU 扩展,以避免破坏现有文件,并-T
消除之间的歧义搬去和搬进否则mv
会受到影响。但请注意,当文件因 原因而未重命名时-n
,您不会收到任何相关错误。
答案2
rename
基于- 并允许使用算术(某些发行版使用此重命名工具的perl
名称):prename
perl
rename 's/(log.)([0-9]+)$/$1.($2+1)/e' <files>
要与 find 结合使用,请使用:
find <search options> -exec rename 's/(log.)([0-9]+)$/$1.($2+1)/e' {} +
编辑以下 Stéphane 的评论:
未排序的输出find
可能确实会给您带来麻烦,最好事先对其进行排序。我们可以对给定的名称模式使用反向 (!) 排序及其版本编号选项:
find <search parpameters> -print0 |\
sort -rzV |\
xargs -r0 rename 's/(log.)([0-9]+)$/$1.($2+1)/e'