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

 mobiledu2502858393 发布于 2022-12-31 15:36

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

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

我尝试了以下循环文件(其名称中包含空格):

#!/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命令来修复目录中的文件名),但它只有在所有文件都在同一目录中时才有效,而不是我目前拥有的大子目录结构.

谢谢.

1 个回答
  • 您不需要使用IFS.只需附上您的参数""以防止分词:

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

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

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

    请参见单词拆分和参数扩展.

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

    要使用globs启用递归,请启用globstar:shopt -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为输出分隔符而不是newline(0x0A)-print0.

    也可以使用字符集:

    [: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:]|!@#$%^&*()]}"
    

    2022-12-31 15:38 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有