【问题标题】:File name without extension in bash for loopbash for循环中没有扩展名的文件名
【发布时间】:2011-11-10 17:33:49
【问题描述】:

在这样的 for 循环中:

for f in `ls *.avi`; do echo $f; ffmpeg -i $f $f.mp3; done

$f 将是完整的文件名,包括扩展名。例如,对于 song1.avi,命令的输出将是 song1.avi.mp3。有没有办法只从 for 循环中获取歌曲 1,而无需 .avi?

我想有办法使用 awk 或其他类似工具来做到这一点,但我希望有更直接的方法。

谢谢

【问题讨论】:

  • 顺便说一句,你想失去反引号的无用使用。正确且惯用的语法是for f in *.avi; do ...
  • 更不用说 - 如果文件名中有空格(尽管这是一种邪恶的做法),您实际上应该像 ls *avi | while read f; do (...); done 一样。然后到处引用"$f"。只是说。

标签: bash


【解决方案1】:

使用 bash 参数扩展

${f%%.*}

请注意,您需要贪心版本,因为文件名中有多个点。

来自 bash 手册:

${parameter%word}

${parameter%%word}

单词被扩展以产生一个模式,就像在文件名扩展中一样。如果模式匹配参数扩展值的尾随部分,则扩展结果是具有最短匹配模式('%' 情况)或最长匹配模式('%%' 情况)的参数值删除。如果参数是'@'或'',模式移除操作将依次应用于每个位置参数,扩展是结果列表。如果 parameter 是下标为“@”或“”的数组变量,则模式移除操作依次应用于数组的每个成员,展开就是结果列表。

【讨论】:

  • 使用${f%.*}——如果你使用${f%%.*}并且$f是“one.two.avi”,你会得到“one”而不是“one.two”
【解决方案2】:

应该这样做:

for i in *.m4a; do
  ffmpeg -i $i ${i%%.*}.mp3
done

【讨论】:

  • 对于已知的扩展名(如for 列表中),您可以使用basename $i .m4a(反引号),但是一旦您记住了%.*(可以说,百分之一更好) ,你不会再回头。
  • 由于缺少引号,这有点错误。将其设为ffmpeg -i "$i" "${i%%.*}.mp3" 将修复对带有空格的文件名的支持。 (顺便说一句,这些是shellcheck.net 可以发现的问题)。
猜你喜欢
  • 2020-09-27
  • 2011-07-03
  • 2014-02-05
  • 2012-12-24
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 2011-10-07
  • 2016-07-23
相关资源
最近更新 更多