首页 文章

BASH - 递归重命名包含无效/非打印字符的文件

提问于
浏览
0

我根据包含该书的PDF文件中的 Headers 手动重命名了许多文件(电子书) . 我这样做是通过手动复制PDF阅读器中的多行文本,然后在Nautilus中重命名文件 . 我想将这些全部添加到SVN仓库中,但由于包含 0x0A (换行符)字符的多个PDF文件名本身,add命令失败 . 我的语言环境在我的 .bashrc 文件中设置为UTF8,似乎Ubuntu的Nautilus文件资源管理器实用程序允许我将非打印字符粘贴到文件名( is it possible to disable this? )中 .

无论如何,我现在有一个包含子目录,PDF,PDF子目录等子目录的大型目录 . 有没有办法以递归方式遍历目录结构并从文件名中删除任何非打印字符(即:换行符)?

我尝试了以下循环文件( which contain spaces in their names ):

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for f in *
do
  echo "Renaming $f"
  mv ${f} $(echo ${f} | sed 's/\n//g')
done
IFS=$SAVEIFS

但是,文件名中带有换行符的文件将打印在两个单独的行中,就好像它们是单独的条目一样 . 我在SO(sed command to fix filenames in a directory)上找到了一个可能的解决方案,但它只有在所有文件都在同一目录下才有效,而不是我目前拥有的大子目录结构 .

谢谢 .

1 回答

  • 5

    您不需要使用IFS . 只需将您的参数括在 "" 周围以防止分词:

    mv "${f}" "$(echo "${f}" | sed 's/\n//g')"
    

    此外,您可以使用特殊参数扩展来删除换行符:

    mv "${f}" "${f//$'\n'}"
    

    Word SplittingParameter Expansion .

    注意:只有开放变量受IFS影响 . 当它们展开时,立即的glob模式如 * 不会分裂 .

    要使用globs启用递归,请启用 globstarshopt -s globstar . 那你可以做

    for f in /path/to/dir/**; do
        [[ ! -d $f ]] && mv "$f" "${f//$'\n'}"  ## Test lets it process files only.
    done
    

    使用 find

    find -type f '/path/to/dir' -print0 | while IFS= read -rd '' f; do
        mv "$f" "${f//$'\n'}"
    done
    

    与使用流程替换相同:

    while IFS= read -rd ''; do
        mv "$f" "${f//$'\n'}"
    done < <(exec find -type f '/path/to/dir' -print0)
    

    使用 IFS=read 禁用输入中的单词拆分 . -r 禁用解释反斜杠引号, -d '' 将分隔符设置为 0x00 . 它适用于 find ,它将 0x00 设置为输出分隔符,而不是带有 -print0 的换行符( 0x0A ) .

    也可以使用字符集:

    [:alpha:]   Alphabetic characters.
    [:blank:]   Space and TAB characters.
    [:cntrl:]   Control characters.
    [:digit:]   Numeric characters.
    [:graph:]   Characters that are both printable and visible.
    [:lower:]   Lowercase alphabetic characters.
    [:print:]   Printable characters (characters that are not control characters).
    [:punct:]   Punctuation characters (characters that are not letters, digits,
    [:space:]   Space characters (such as space, TAB, and formfeed, to name a few).
    [:upper:]   Uppercase alphabetic characters.
    [:xdigit:]  Characters that are hexadecimal digits.
    

    你可能想要:

    mv "$f" "${f//[[:cntrl:]]}"
    

    要么

    mv "$f" "${f//[^[:print:]]}"  ## Does not only include control chars but probably some if not all extended chars as well.
    

    你也可以加入他们:

    mv "$f" "${f//[[:cntrl:]|!@#$%^&*()]}"
    

    当然在进行实际运行之前先测试它们:

    echo mv "$f" "${f//[[:cntrl:]|!@#$%^&*()]}"
    

相关问题