ZSh 脚本批量处理包含空格和替换扩展名的文件名

ZSh 脚本批量处理包含空格和替换扩展名的文件名

是否有一个 zsh 脚本可以将一种音乐格式的目录文件转换为 Ogg opus 格式。这文件名中包含空格

例如,一个目录包含10个扩展名为*.wma的文件

文件转换为*.wav格式使用ffmpeg -i filename.wma filename.wav

文件*.wav被转换为作品使用opusenc --bitrate 160 filename.wav filename.opus

更新ffmpeg -i filename.wma -c:a libopus -b:a 128k filename.opus用一个命令转换文件

部分工作的脚本将处理当前目录中从 .wma 到 .wav 的文件名,即使带有空格。但是,.wav添加了扩展名而不是替换 *.wma 文件扩展名

该脚本被添加到一个名为的文件中convert,并且该文件变得可执行

IFS=$'\n'
for x in *.wma ; do
  echo $x
  ffmpeg -i "$x" $x.wav
done

尝试使用Zsh 修饰符将文件扩展名替换为:(${x:e}".wav在 ilkkachu 的建议后我也尝试过${x:r}".wav

IFS=$'\n'
for x in *.wma ; do
  ffmpeg -i "$x" "${x:e}".wav
done

从名为的文件调用此文件convert,将返回以下错误

./convert: 3: Bad substitution

同样的错误发生在

IFS=$'\n'
for x in *.wma ; do
  ffmpeg -i "$x" "${x:r}".wav
done

我认为语法不太好写,或者当文件名有空格时修饰符不起作用。或者关于 zsh 我还有很多东西需要学习:)

是否有正确的方法来替换 Zsh 中的文件扩展名(当文件名包含空格时)

谢谢。

答案1

虽然您的问题是您将脚本解释为 ,sh而不是zsh, in zsh,但您可以在此处使用zmv

#! /bin/zsh -
autoload zmv
zmv -P ffmpeg -o -i './(*).wma' './$1.wav'

zmv通常会进行批量重命名,但也可以进行批量复制/链接或批量任何操作(如果给出执行该操作的命令名称)任何事物

您可以从它在执行任何操作之前执行的少数保护措施中受益(检查目标文件是否不存在或两个源文件是否映射到同一目标)。

另请注意./前缀,以避免以 开头的文件名出现问题-,或者通常可以解决ffmpeg.

在任何情况下,IFS=$'\n'您的代码中的 都没有任何作用,因为您没有使用 IFS 分词(仅在命令替换和$=paramzsh 中完成),也没有使用诸如"$array[*]"将数组元素与 的第一个元素连接之类的东西$IFS,无论如何zsh,您//宁愿使用s[sep]参数扩展标志来分割或加入而不是全局更改。另请注意,换行符与文件名中的任何字符一样有效。f0j[sep]$IFS

答案2

要使用 Zsh 修饰符(和其他 zsh 特定语法),添加到文件的脚本应首先将其定义为 zsh 脚本

#!/usr/bin/zsh

which zsh(可选)如果不确定您的操作系统使用此位置,请首先检查 zsh 的位置

添加此行还可以在编辑器中打开文件时添加特定的 zsh 语法突出显示

shell 变量 IFS(内部字段分隔符)确定在分割字符串序列(例如目录列表)时如何识别单词边界。

在 zsh 中将IFS 设置为$'\n'允许使用包含空格的文件名

IFS=$'\n'

使用for循环将迭代当前目录中的所有文件,使用通配符 -*.wma对于当前目录中的该文件扩展名或**/*.wma当前目录和子目录

#!/usr/bin/zsh

IFS=$'\n'
for x in *.wma ; do
  ffmpeg -i "$x" "${x:r}".wav
done

ffmpeg 可以使用libopus音频编解码器转换为 opus 文件,因此不需要转换为 opusenc 工具支持的格式。

ffmpeg -i original-file.wma -b:a 128k -c:a libopus ouptut-file.opus

其中-b:a是音频比特率,-c:a是音频编解码器

将所有这些放在一起,最终的脚本是:

#!/usr/bin/zsh

IFS=$'\n'
for x in *.wma ; do
  ffmpeg -i "$x" -b:a 128k -c:a libopus "${x:r}".opus
done

相关内容