我知道您可以执行以下操作以使用以下方式重命名单个文件夹中的所有文件名:
for file in 1_*; do
mv "$file" "${file/1_/}"
done
但是,是否可以跨多个文件夹执行此操作?例如,它将搜索当前目录中的所有文件夹并进行更改。
我有bash
版本4.3
一个健壮的解决方案,假设您具有GNU或BSD / OSXfind
:
find . -type f -name '1_*' -execdir sh -c 'echo mv -- "$1" "${1#1_}"' _ {} \;
注意:
-为了安全起见,这只会回显mv
命令;删除echo
以执行实际的重命名。
-OP的替代"${file/1_/}"
已更改为POSIX-compatible "${file#1_}"
,实际上更接近意图。
-如果您确实需要系统上可能支持或可能不支持的替换,例如"${file/1_/}"
,最好显式调用已知的支持它的shell 。-符号链接被忽略(文件和目录);用于将它们包括在内(既是要重命名的潜在文件,又是下降到目录的符号链接)。sh
bash
find -L ...
find
find . -type f -name '1_*'
在当前目录的()子树中查找-type f
名称与1_*
(-name '1_*'
)匹配的所有文件().
。-execdir
在当前文件所在的子目录中执行传递给它的命令。sh -c 'echo mv -- "$1" "${1#1_}"' _ {} \;
调用默认的shell(sh
):
-c
)
mv -- "$1" "${1#1_}"
有效地1_
从第一个位置参数($1
)表示的文件名中删除前缀。_
(sh
将分配给$0
,在这里不重要){}
外壳将绑定到的当前文件的路径$1
;\;
只是终止-execdir
的论点。请注意,请--
确保不会将任何以。开头的文件名-
误认为是选项mv
(通过类似的用法)。
-execdir
不符合POSIX;如果兼容POSIX的变体因此比较麻烦:
find . -type f -name '1_*' -exec sh -c \
'cd -- "${1%/*}" && f=${1##*/} && echo mv -- "$f" "${f#1_}"' _ {} \;
cd -- "${1%/*}"
更改到手头文件所在的目录。
cd -- "$(dirname -- "$1")"
通常更健壮,但效率较低;由于我们知道在这种情况下,$1
它始终是路径而不是单纯的文件名,因此我们可以使用更有效的cd -- "${1%/*}"
。f=${1##*/}
从手边的文件路径中提取纯文件名。性能说明:
上面的解决方案很简洁,但是效率很低,因为必须为每个匹配的文件生成一个shell实例。
一个潜在的加速是使用的一个变种峰的做法,但只有当你避免调用外部公用事业的while
循环(除mv
):
find . -type f -name '1_*' | while IFS= read -r f; do
new_name=${f##*/} # extract filename
new_name=${new_name#1_} # perform substitution
d=${f%/*} # extract dir
echo mv -- "$f" "$d/$new_name" # call mv to rename
done
上面的假设有冒用嵌入的换行符破坏文件名的风险(非常罕见);使用GNU或BSDfind
可以解决此问题。
使用这种方法,仅产生一个shell实例,该实例将在循环中处理所有匹配的文件名-只要在循环中调用的唯一外部实用程序为mv
,这通常会比使用find
-only的解决方案更快-exec[dir]
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句