【问题标题】:BASH - Recursively rename files containing invalid/non-printing charactersBASH - 递归重命名包含无效/非打印字符的文件
【发布时间】:2014-09-21 14:31:20
【问题描述】:

我根据包含该书的 PDF 文件中的标题手动重命名了许多文件(电子书)。我通过在我的 PDF 阅读器中手动复制多行文本,然后在 Nautilus 中重命名文件来做到这一点。我想将这些全部添加到 SVN 存储库中,但由于包含 0x0A(换行符)字符的多个 PDF 的文件名本身,添加命令失败。我的.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 command to fix filenames in a directory) 上找到了一个可能的解决方案,但它只有在所有文件都在同一个目录中时才有效,而不是我目前拥有的大子目录结构。

谢谢。

【问题讨论】:

  • 根据文件名,用空格替换每个换行符可能更有意义。

标签: bash sed filenames rename


【解决方案1】:

您不需要使用 IFS。只需将您的论点附在 "" 周围即可防止分词:

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

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

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

请参阅 Word SplittingParameter Expansion

注意:只有开放变量受 IFS 影响。像 * 这样的即时 glob 模式在展开时不会拆分。

要启用 glob 递归,请启用 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 设置为输出分隔符,而不是-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:]|!@#$%^&*()]}"

【讨论】:

  • +1 但也许还展示了如何使用find 在目录树中执行此操作。
  • 太棒了。另外,感谢您提供基于 find 的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 2013-02-07
相关资源
最近更新 更多