Bash 用于从跨多行的文本块中提取信息的脚本
Bash script to extract information from a block of text spanning multiple lines
我正在尝试使用 bash
脚本中的 mkvinfo
从 MKV
文件中提取曲目信息。输出是一长串带有重复模式的行,作为各种轨道类型的各种轨道属性的分隔符。曲目示例是:
…
| + A track
| + Track number: 6 (track ID for mkvmerge & mkvextract: 5)
| + Track UID: 11555278830806058806
| + Track type: subtitles
| + (Unknown element: TrickTrackFlag; ID: 0xc6 size: 3)
| + Enabled: 1
| + Default flag: 0
| + Forced flag: 0
| + Lacing flag: 0
| + MinCache: 0
| + Timecode scale: 1
| + Name: Spanish
| + Language: spa
| + Codec ID: S_TEXT/UTF8
| + (Unknown element: TrackAttachmentLink; ID: 0x7446 size: 11)
| + Codec decode all: 1
| + A track
| + Track number: 7 (track ID for mkvmerge & mkvextract: 6)
…
给定轨道类型可以有多个实例,并且轨道的行数有些可变。我需要从特定轨道类型中提取某些轨道属性。例如,如果我想找到 subtitles
轨道类型的所有实例并提取 Track number
和 Codec ID
,我可以通过 grep:
管道化结果
mkvinfo "file.mkv" | grep "subtitles" -B 2 | grep "Track number"
这会输出包含所有字幕轨道的轨道编号的行。我必须将这些行放入一个数组中并过滤它们以获得第一个数字,这样我就可以将它与 mkvpropedit
一起使用,这需要第一个数字。
同样:
mkvinfo "file.mkv" | grep "subtitles" -A 10 | grep "Codec ID: " | sed 's/^.**: //'
输出所有字幕轨道的编解码器 ID。
这很好用 IF 我确切地知道有多少行 before/after 包含 subtitles
的行。问题是,要包含的确切行数因文件而异。所以我需要做的是输出 | + A track
和以 |+
OR | +
OR EOF
开头的行之间的整个行块。我还需要过滤块以提取第一个 Track number
和 Codec ID
。我尝试使用 | grep -Eo [0-9]+ | head -1
来提取每首曲目的第一个数字,但它只适用于找到的第一首曲目并退出。如果有一种方法可以使其适用于一行中的所有曲目,那将很有帮助。我使用 sed
给出的第二个示例适用于 Codec ID
.
底线问题是:
How can I extract specific properties of specific track types, such as the example given, and put them into an array or arrays for further processing?
我希望能够满足以下条件:
- 我想使用现有的
bash
(GNU bash,版本 4.3.30(1)-release (x86_64-apple-darwin12.5.0))实用程序,例如 sed
, awk
、grep
、……
- 我不想创建 'intermediate file'
- 我想简单地管道
mkvinfo
的输出到各种实用程序
我找到了很多展示如何使用 sed
在两个 单词 之间查找文本块的帖子,但我无法获得与 一起使用的代码=60=]整行或包含空格的字符串。也许有办法做到这一点,但我对 sed
了解不够,无法根据我的情况调整代码。
请详细解释你的代码是如何工作的所以我可以'learn how to fish'所以下次我可以自己做。
当以复杂的方式处理多行时,我选择的工具是awk
。
在每个匹配模式中,我们将匹配保存在一个变量中。
最后,当我们遇到指示新块(| + A track
)的字符串时,或者我们到达流的末尾时,我们打印我们感兴趣的变量的值(轨道号,编解码器 ID),但前提是类型是字幕。
mkvinfo ... | gawk '
match([=10=], /Track number: ([0-9]+)/, m) {TN=m[1]}
match([=10=], /Codec ID: (.*)$/, m) {CI=m[1]}
/Track type: subtitles/ {SUB=1}
/^\| \+ A track$/ {if(SUB) print TN, CI; unset SUB}
END {if(SUB) print TN, CI; unset SUB}'
您需要 gawk
具有匹配功能来捕获括号内的组。
我正在尝试使用 bash
脚本中的 mkvinfo
从 MKV
文件中提取曲目信息。输出是一长串带有重复模式的行,作为各种轨道类型的各种轨道属性的分隔符。曲目示例是:
…
| + A track
| + Track number: 6 (track ID for mkvmerge & mkvextract: 5)
| + Track UID: 11555278830806058806
| + Track type: subtitles
| + (Unknown element: TrickTrackFlag; ID: 0xc6 size: 3)
| + Enabled: 1
| + Default flag: 0
| + Forced flag: 0
| + Lacing flag: 0
| + MinCache: 0
| + Timecode scale: 1
| + Name: Spanish
| + Language: spa
| + Codec ID: S_TEXT/UTF8
| + (Unknown element: TrackAttachmentLink; ID: 0x7446 size: 11)
| + Codec decode all: 1
| + A track
| + Track number: 7 (track ID for mkvmerge & mkvextract: 6)
…
给定轨道类型可以有多个实例,并且轨道的行数有些可变。我需要从特定轨道类型中提取某些轨道属性。例如,如果我想找到 subtitles
轨道类型的所有实例并提取 Track number
和 Codec ID
,我可以通过 grep:
mkvinfo "file.mkv" | grep "subtitles" -B 2 | grep "Track number"
这会输出包含所有字幕轨道的轨道编号的行。我必须将这些行放入一个数组中并过滤它们以获得第一个数字,这样我就可以将它与 mkvpropedit
一起使用,这需要第一个数字。
同样:
mkvinfo "file.mkv" | grep "subtitles" -A 10 | grep "Codec ID: " | sed 's/^.**: //'
输出所有字幕轨道的编解码器 ID。
这很好用 IF 我确切地知道有多少行 before/after 包含 subtitles
的行。问题是,要包含的确切行数因文件而异。所以我需要做的是输出 | + A track
和以 |+
OR | +
OR EOF
开头的行之间的整个行块。我还需要过滤块以提取第一个 Track number
和 Codec ID
。我尝试使用 | grep -Eo [0-9]+ | head -1
来提取每首曲目的第一个数字,但它只适用于找到的第一首曲目并退出。如果有一种方法可以使其适用于一行中的所有曲目,那将很有帮助。我使用 sed
给出的第二个示例适用于 Codec ID
.
底线问题是:
How can I extract specific properties of specific track types, such as the example given, and put them into an array or arrays for further processing?
我希望能够满足以下条件:
- 我想使用现有的
bash
(GNU bash,版本 4.3.30(1)-release (x86_64-apple-darwin12.5.0))实用程序,例如sed
,awk
、grep
、…… - 我不想创建 'intermediate file'
- 我想简单地管道
mkvinfo
的输出到各种实用程序
我找到了很多展示如何使用 sed
在两个 单词 之间查找文本块的帖子,但我无法获得与 一起使用的代码=60=]整行或包含空格的字符串。也许有办法做到这一点,但我对 sed
了解不够,无法根据我的情况调整代码。
请详细解释你的代码是如何工作的所以我可以'learn how to fish'所以下次我可以自己做。
当以复杂的方式处理多行时,我选择的工具是awk
。
在每个匹配模式中,我们将匹配保存在一个变量中。
最后,当我们遇到指示新块(| + A track
)的字符串时,或者我们到达流的末尾时,我们打印我们感兴趣的变量的值(轨道号,编解码器 ID),但前提是类型是字幕。
mkvinfo ... | gawk '
match([=10=], /Track number: ([0-9]+)/, m) {TN=m[1]}
match([=10=], /Codec ID: (.*)$/, m) {CI=m[1]}
/Track type: subtitles/ {SUB=1}
/^\| \+ A track$/ {if(SUB) print TN, CI; unset SUB}
END {if(SUB) print TN, CI; unset SUB}'
您需要 gawk
具有匹配功能来捕获括号内的组。