我有一堆带有相关字幕的视频文件。我正在尝试编写一个 bash 脚本,将字幕和视频合并到 matroshka 容器中。
输入视频文件名为“videoName.mkv”、“videoName.webm”或videoName.mp4,具体取决于原始容器。输入字幕文件名为“videoName.languageCode.vtt”。输出视频文件名为“subsvideoName” .mkv"
这是我想出的脚本:
#!/bin/bash
for video in *; do
if [[ $video =~ \.(mkv|webm|mp4)$ ]]; then
[[ $video =~ \.(mkv|webm|mp4) ]]
format=${BASH_REMATCH}
[[ $video =~ .*[^$format] ]]
name=${BASH_REMATCH}
echo $name
arsubs=()
for subs in *; do
echo "$subs"
if [[ $subs =~ $name.*\.vtt$ ]]; then
[[ $subs =~ \.[a-zA-Z0-9\-]*\.vtt$ ]]
lang=$BASH_REMATCH
[[ $lang =~ [^\.][a-zA-Z0-9\-]*[^\.] ]]
lang=$BASH_REMATCH
if [[ $lang =~ [a-z]*[^a-z]+ ]]; then
lang=$BASH_REMATCH
[[ $lang =~ [a-z]* ]]
lang=$BASH_REMATCH
fi
arsubs+=(--language 0:$lang)
arsubs+=("$subs")
fi
done
nameout=subs$name.mkv
mkvmerge -o "$nameout" "$video" "${arsubs[@]}"
fi
done
我遇到问题的正则表达式是 [[ $subs =~ $nom.*.vtt$ ]] (第 13 行),如果文件名包含正则表达式标签(例如“+”或“$”),则该正则表达式不匹配。如果文件名不包含此类字符,则脚本运行良好。
我环顾四周,但我能找到的唯一解决方案需要转义有问题的字符,我认为这不能在这里完成。
感谢您的时间。
答案1
你似乎以一种非常迂回的方式来解决这个问题,有太多的正则表达式匹配。
那这个呢?
#!/bin/bash
shopt -s nullglob
for video in *.mkv *.webm *.mp4; do
name=${video%.*}
set -- "$name".*.vtt
if [ -e "$1" ]; then
lang=${1#$name.}
lang=${lang%.vtt}
mkvmerge -o "subs$name.mkv" "$video" --language "0:$lang" "$1"
fi
done
这假设您想要使用.vtt
为给定找到的第一个文件$name
(如果有多个.vtt
文件,例如对于多种语言)。
该循环遍历与 、 和 三个模式中的任何一个匹配的*.mkv
所有*.webm
名称*.mp4
。这样,您就不必针对这些后缀测试循环变量来确定它是否与其中任何一个匹配。
给定 中的文件名$video
,然后通过简单地删除文件名后缀(无论它是什么)来提取名称部分。这给了我们$name
.
有了set
,我们就可以匹配模式了"$name".*.vtt
。如果此模式至少匹配一个文件名,则该文件名将位于 中,我们通过从匹配文件名的前面和末尾删除来提取其中的语言部分(与模式中的$1
匹配的位)。*
$name.
.vtt
然后我们打电话mkvmerge
提供必要的信息。我们不mkvmerge
如果没有文件,则调用.vtt
(您的代码似乎正在这样做)。
另请注意,如果文件名后缀之前有多个同名文件,例如thing.mp4
和thing.mkv
,则这些文件将产生具有相同名称 ( )mkvmerge
的相同命令。-o
substhing.mkv
.vtt
您可以通过循环遍历文件,然后选择与文件名相对应的您最感兴趣的视频文件格式来解决此问题.vtt
。
不过,您在任何时候都不必使用正则表达式来实现这些目的。
以下是考虑.vtt
给定名称的所有文件的变体:
#!/bin/bash
shopt -s nullglob
for video in *.mkv *.webm *.mp4; do
name=${video%.*}
sub_opts=()
for sub in "$name".*.vtt; do
lang=${sub#$name.}
lang=${lang%.vtt}
sub_opts+=( --language "0:$lang" "$sub" )
done
if [ "${#sub_opts[@]}" -gt 0 ]; then
mkvmerge -o "subs$name.mkv" "$video" "${sub_opts[@]}"
fi
done