递归重命名文件并删除一个字符。

3

有一些文件名包含问号'?',你知道windows对这样的字符有问题。我想使用xarg递归地重命名文件夹中的所有文件。例如:

09 - grand hall?_10.mp3

应该是

09 - grand hall_10.mp3

顺便问一下,您要删除空格吗? - Shep
这不错。那么该怎么办? - mahmood
解决方案必须使用xarg吗? - Shep
这些目录中是否包含空格或 ? 字符? - Shep
我不知道。我以为我必须使用xargs。 - mahmood
3个回答

3

for file in $(find 文件夹 -name '*.mp3'); do
  mv -v "$file" $(echo "$file" | tr ? _);
done


上述代码存在空格问题; 下面的改写更好:

find 文件夹 -name '*.mp3' -exec echo "'{}'" \; |
  while read file; do
    echo -n "mv -v $file " && echo $file | tr ? _;
done | sh

代码的思路是先找到所有符合条件的文件,在将其用引号输出。再通过while循环为每个文件构造一个mv指令,最后将结果重定向到新的Shell中。

虽然看起来有些丑陋,但要是你不喜欢这个答案,那也就不该问这个问题了。 :-)


空格会产生噪音,如何去除它们? - mahmood
@AdamLiss 我在这个代码中修复了$file中的一些空格问题,但是for file in $(find _folder_ -name '*.mp3')仍然存在重新标记化的问题。你可以尝试基于find -print0管道到read -d ''的方法。 - je4d
@je4d 分词已经修复,格式化也按预期进行。感谢您的帮助! - Adam Liss
@AdamLiss 更接近了..但文件名理论上可以包含换行符,传递列表的唯一绝对可靠的方法是使用“null”分隔符。您还引入了一个代码执行问题,因为我可以创建一个像"file $(我的要运行的代码)name"这样的文件名,您的管道sh将最终运行“我的要运行的代码”! - je4d
只是出于好奇,单引号会正确处理换行符吗?如果你的文件名中有换行符,那么你就被解雇了。 :-) - Adam Liss
1
@AdamLiss 并不是一般情况...文件名也可能包含单引号! 要解决这个问题,首先避免使用管道到 sh,那几乎总是一个坏主意。使用 find ... -print0 以 null 字节分隔打印文件名。然后将其管道传递给 while read -d '' filename; do ...; done 循环。-d '' 使 read 使用 null 字节分隔。 - je4d

2

这个看起来非常丑陋,但我把它当作一个个人挑战来完成一行代码的工作。 :-)

find 文件夹 -name '*.mp3' -exec \
  sh -c "echo -n 'mv \"{}\" ' && echo \'{}\' | tr ? _" \; | sh

策略是找到文件,并使用echo构造每个文件的mv命令及其名称的引用符,然后将输出导入到shell。


1
找到:缺少“-exec”的参数。 - mahmood
@mahmood: 已修复。感谢您的提醒! - Adam Liss
这是迄今为止对这个问题最优雅的答案。谢谢! - Benoit Duffez
@Bicou:或许在某种程度上可以称之为“优雅”,很高兴它对你有用。 - Adam Liss

0
这个一行代码应该可以处理包含单引号、双引号和空格的文件名:
(IFS=\0;find . -name \*\\?\* -type f -print0| while read -d '' f;do mv -v $f $(echo $f|tr -d \?);done)

解释:

  1. find 只搜索文件名包含 '?' 的文件。
  2. \0 设置为 IFS 的分隔符,find(通过 -print0)和 read(通过 -d '')可以处理包含特殊字符的文件名,如单引号、双引号、空格等。
  3. 最外层的括号将整个命令执行放在子 shell 中,因此保持当前 shell 的 IFS 不变。
  4. 脚本中的 . 可以替换为任何其他目录。
  5. 这个脚本有一个非常小的问题:如果一个文件的名称和其父级之一的名称都包含 '?',它可能会出错。虽然可以处理这种情况,但脚本会变得更加丑陋和难以阅读。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接