除了隐藏的“.”之外,还有什么可能呢?来自重命名脚本的文件和目录?

除了隐藏的“.”之外,还有什么可能呢?来自重命名脚本的文件和目录?

我有一个脚本可以重命名每个目录和文件,去掉空格。它以递归方式执行:

#!/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问题。*
  • 如果存在一些冲突(例如当同时存在 aa b ca_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 '')

这里,

  • 将语言环境设置为Cso*匹配任何字节序列,而不仅仅是那些在用户语言环境中形成有效字符的字节序列,并且?匹配单个字节。但请注意,消息(错误、提示...)将以英语而不是用户的语言发出。
  • -name '.?*' -prune -o ...跳过隐藏文件并告诉find不要进入隐藏目录。
  • 传递-imv以防止无意中破坏文件。
  • 通过 fd 3 而不是 stdin 传递文件列表,因此mv -i提示有效。
  • 使用tac -s ''代替sort -rz来反转输出,以确保叶子在它们所在的分支之前被重命名。
  • dirname将/替换basename为标准${var##pattern}${var%pattern}参数扩展运算符。
  • 还传递-rto 来read禁用其对反斜杠的特殊处理。
  • 确保 for 为read $IFS空,这样它就不会从输入记录中删除尾随空格。

相关内容