我有一个脚本可以重命名每个目录和文件,去掉空格。它以递归方式执行:
#!/bin/bash
find -name "* *" -print0 | sort -rz | \
while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
当我在目录中运行它时~
,该脚本对以下项目进行了意外的重命名:
./.cache/google-chrome/Default/Storage/ext/nmmhkkegccagdldgiimedpiccmgmieda/def/Code Cache
./.cache/google-chrome/Default/Storage/ext/gfdkimpbcpahaombhbimeihdjnejgicl/def/Code Cache
./.cache/google-chrome/Default/Code Cache
我希望我的脚本排除以.
重命名开头的任何目录或文件。你会如何编写这样的脚本?为此目的是否需要使用正则表达式?
答案1
无需过多查看管道中的其他命令,您可以避免find
输入任何具有隐藏名称的目录:
find . ! -path . -name '.*' -prune -o -name '* *' -print0 | ...
这将从.
搜索树中删除名称开头的所有目录,.
目录(当前目录)除外。它还将不再找到隐藏的名称。
查看了其余代码rename
后,我建议使用(Perl 变体):
find . ! -path . -name '.*' -prune \
-o -type f -name '* *' -execdir rename -n -v 'tr/ /_/' {} \;
这将搜索包含空格的文件名,然后用下划线替换其中的所有空格,同时忽略隐藏名称并且不进入隐藏目录。
rename
调用该实用程序-n
以阻止它实际执行任何操作(这是“试运行”)。-n
当您确信它正在做正确的事情时将其删除。
如果没有rename
,你会做类似的事情
find . ! -path . -name '.*' -prune \
-o -type f -name '* *' -exec bash -c '
for pathname do
filename=${pathname##*/}
echo mv "$pathname" "${pathname%/*}/${filename// /_}"
done' bash {} +
也就是说,调用一个内联bash
脚本来迭代找到的名称,通过将空格更改为下划线来重命名每个名称。
echo
当您确信这样做是正确的时,请删除。
答案2
只需zsh
使用zmv
:
#! /bin/zsh -
autoload -Uz zmv
zmv '(**/)(* *)' '$1${2// /_}'
zmv
默认情况下跳过隐藏文件和隐藏目录中的文件(除非您将(#qD)
限定符传递给第一个参数),- 它处理文件深度优先(
sort -rz
不保证您可以为此工作并且-prune
与不兼容-depth
) - 我们不需要调用
dirname
/basename
(如果有一些文件名以换行符结尾,这将是昂贵的并且无法正常使用命令替换)。 - 它不存在不匹配任意字节序列的
find
问题。*
- 如果存在一些冲突(例如当同时存在 a
a b c
和a_b c
文件都将重命名为时a_b_c
),它将在开始时检测到它并在进行任何重命名之前中止。
要用 GNU 工具来做一些事情,就像这样:
#! /bin/bash -
export LC_ALL=C
while IFS= read <&3 -rd '' file; do
dir=${file%/*} name=${file##*/}
mv -i -- "$file" "$dir/${name// /_}"
done 3< <(
find . -name '.?*' -prune -o -name '* *' -print0 |
tac -s '')
这里,
- 将语言环境设置为
C
so*
匹配任何字节序列,而不仅仅是那些在用户语言环境中形成有效字符的字节序列,并且?
匹配单个字节。但请注意,消息(错误、提示...)将以英语而不是用户的语言发出。 -name '.?*' -prune -o ...
跳过隐藏文件并告诉find
不要进入隐藏目录。- 传递
-i
到mv
以防止无意中破坏文件。 - 通过 fd 3 而不是 stdin 传递文件列表,因此
mv -i
提示有效。 - 使用
tac -s ''
代替sort -rz
来反转输出,以确保叶子在它们所在的分支之前被重命名。 dirname
将/替换basename
为标准${var##pattern}
和${var%pattern}
参数扩展运算符。- 还传递
-r
to 来read
禁用其对反斜杠的特殊处理。 - 确保 for 为
read
$IFS
空,这样它就不会从输入记录中删除尾随空格。