查找、执行和剥离文件名的扩展名

5

你有没有想过为什么这个命令不起作用?顺便说一下,我正在尝试剥离当前目录中所有csv文件的扩展名。

find -type f -iname "*.csv" -exec mv {} $(basename {} ".csv") \;

尝试了许多变体,包括参数扩展、xargs...即使这样,一切都是徒劳的。

2个回答

9
这应该可以:
 find ./ -type f -iname "*.csv" -exec sh -c 'mv {} $(basename {} .csv)' \;

find 能够替换 {} 成为它的结果,因为引号阻止了子 Shell 在 find 完成前执行。然后它执行 -exec 部分。


你的命令不能正常工作的问题在于 $(basename {} ".csv") 在一个子 Shell 中执行(-> $())并且事先被计算出来了。如果我们逐步查看命令执行过程,你会看到发生了什么:

  1. find -type f -iname "*.csv" -exec mv {} $(basename {} ".csv") \; - 你的命令
  2. find -type f -iname "*.csv" -exec mv {} {} \; - 子 Shell 已经被计算出来了($(basename {} ".csv") 返回 {},因为它将 {} 解释为字面量)
  3. find -type f -iname "*.csv" -exec mv {} {} \; - 现在可以看到:移动实际上什么也没做

1
请注意,如果任何文件名包含空格或其他特殊字符,则嵌入{}将失败。可以通过使用-exec sh -c 'mv "$1" $(basename "$1" .csv)' sh {} \;来解决此问题,以便sh将文件作为参数$1接收。末尾的额外的sh是为了将$0设置为通常设置的sh - John Kugelman
@JohnKugelman > “like it would normally be set to”。您能否详细说明在我们通过-exec调用sh并利用$1时,这为什么很重要? - Ari
1
@Ari 它与正常调用 sh$0 的设置相匹配。这样,您就可以获得与正常情况下相同的错误消息,例如,如果您拼错了 mv,则会出现 sh: mvv: command not found,因为它们都带有 "$0: " 前缀。 - John Kugelman

2
首先,请确保您没有子目录;不带额外参数的find命令会自动递归到任何下面的目录中。
简单方法:如果您有足够少的文件,只需使用全局通配符(*)操作符,并利用rename
$ rename 's/.csv$//' *.csv

如果您有太多文件,可以使用find,也许还需要使用xargs
$ find . -maxdepth 1 -type f -name "*.csv" | xargs rename 's/.csv$//'

如果你想要真正安全,请告诉 findxargs 使用 null-bytes 进行分隔,这样你就不会因为奇怪的文件名(如带有空格或换行符)而导致进程出错:
$ find . -maxdepth 1 -type f -name "*.csv" -print0 | xargs -0 rename 's/.csv$//'

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