将电子邮件文件从 .txt 递归重命名为 .eml

将电子邮件文件从 .txt 递归重命名为 .eml

目录“$d”包含数千个扩展名为.txt 的电子邮件文件。要在我的电子邮件客户端中打开它们,我需要将它们重命名为 .eml

此命令能否正确重命名它们:

find "${d}" -type f -name '*.txt' | while read f; do mv -vn "${f}" "${f%.*}".eml; done

还是有更好、更稳健的方法来做到这一点?

我想不出一种优雅的方法来使用:

-exec ...{}... \;

答案1

您的解决方案通常没问题,但它会在换行符上中断。这是一个稍微更健壮的 bash4+ 解决方案:

shopt -s globstar nullglob
for file in **/*.txt; do
    mv "$file" "${file%.*}.eml"
done

答案2

我想你应该没问题

find "$d" -name \*.txt -exec rename .txt .eml {} \;

甚至

for f in *.txt; do rename .txt .eml "$f"; done

如果所有文件都在同一目录中。

答案3

bash是的,假设您使用的是具有类似语法的 shell,您的命令将会起作用。将来,当您考虑使用这样的大命令时,请记住您可以使用echo预览结果命令行。即,您可以放在echo前面mv,运行管道并查看命令是什么。如果它们看起来不错,请删除echo并真正运行该命令。

答案4

在 zsh 中,zmv让这变得容易。输入autoload -U zmv您的~/.zshrc,然后使用以下几种方法之一指定替换文本,该文本与当前目录和子目录中**/*.txt具有扩展名的文件相匹配:txt

zmv '**/*.txt' '$f:r.eml'
zmv '**/*.txt' '${f%.*}.eml'
zmv '(**/)(*).txt' '$1$2.eml'
zmv -w '**/*.txt' '$1$2.eml'

如果您没有 zsh,但有 bash ≥4 或 ksh93,则可以使用**递归遍历子目录,然后循环匹配。您需要**首先shopt -s globstar使用 bash (将其放入您的~/.bashrc)或set -o globstarksh (将其放入您的~/.kshrc)中激活 glob 模式。这也适用于 zsh(无需事先设置)。

for f in **/*.txt; do mv -- "$f" "${f%.*}.eml"; done

请注意,这会重命名所有文件,而不仅仅是常规文件。如果您有目录或其他非常规文件并且希望保持它们不变:

zmv -Q '**/*.txt(.)' '$f:r.eml'
for f in **/*.txt; do [[ -f $f ]] && mv -- "$f" "${f%.*}.eml"; done

由于没有 POSIX 之外的 shell 功能,您需要调用find来遍历子目录。您的解决方案很脆弱,因为它会在包含反斜杠、尾随空格或换行符的文件上中断。您可以使用以下命令修复尾随空格和反斜杠问题while IFS= read -r f; do …但管道输出find本质上会在换行符上中断。代替使用-exec。在 Linux 上,您可以使用该rename实用程序 (无论您的发行版带有什么)。在 Debian、Ubuntu 及其衍生版本上:

rename 's/\.txt$/.eml/' **/*.txt
find . -name '*.txt' -type f -exec rename 's/\.txt$/.eml/' {} +

在其他发行版上,只要.txt中间不包含任何文件名(因为rename替换了源字符串的第一次出现):

rename .txt .eml **/*.txt
find . -name '*.txt' -type f -exec rename .txt .eml {} +

整个过程中仅使用 POSIX 功能,调用 shell 对名称执行转换。

find . -name '*.txt' -type f -exec sh -c 'for f; do mv "$f" "${f%.*}.eml"; done' _ {} +

如果您的find版本太旧而无法支持-exec … +,则需要为每个文件调用一个 shell,这使得代码更简单但速度更慢。

find . -name '*.txt' -type f -exec sh -c 'mv "$0" "${0%.*}.eml"; done' {} \;

相关内容