使用awk打印匹配特定模式的行

3

我有一个类似下面的mpd文件,文件名为mpd

<BaseURL>01/</BaseURL>
   <SegmentList timescale="1000">
   <SegmentURL media="1.ts" mediaRange="0-6003779"/>
   <SegmentURL media="2.ts" mediaRange="0-7313387"/>
   <BaseURL>02/</BaseURL>
   <SegmentList timescale="1000">            
   <SegmentURL media="1.ts" mediaRange="0-6003779"/>
   <SegmentURL media="2.ts" mediaRange="0-7313387"/>
   <BaseURL>01/</BaseURL>
   <SegmentList timescale="1000">
   <SegmentURL media="3.ts" mediaRange="0-6003779"/>
   <SegmentURL media="4.ts" mediaRange="0-7313387"/>    
   <BaseURL>02/</BaseURL>
   <SegmentList timescale="1000">
   <SegmentList timescale="1000">
   <SegmentURL media="3.ts" mediaRange="0-6003779"/>
   <SegmentURL media="4.ts" mediaRange="0-7313387"/>

我想要将每个<BaseURL><segment URL>行保存到不同的文件中。

我的期望输出是

<BaseURL>01/</BaseURL>
    <SegmentURL media="1.ts" mediaRange="0-6003779"/>
    <SegmentURL media="2.ts" mediaRange="0-7313387"/>
    <SegmentURL media="3.ts" mediaRange="0-6003779"/>
    <SegmentURL media="4.ts" mediaRange="0-7313387"/>

我尝试了以下命令,但效果与预期不符,希望得到帮助。下面的命令只会打印mpd文件中最后一个片段URL。我对awk为什么只打印最后几个条目感到困惑。

  awk '
# start writing to new segment file segment.01 etc
match($0, /<BaseURL>([0-9]+)\/<\/BaseURL>/, m) {
  base=m[1]
  close(segf)
  segf="segment." base
  print "write segments to " segf
  print >segf
}
/<SegmentURL / {print >segf}
END {close(segf)}
' mpd

你说你想把它们保存在不同的文件中,但你却把所有东西都保存到了“segment.01”中。你的写入不同文件的代码在哪里?另外,你只匹配了具有0和1字符序列的<BaseURL>行,而无法匹配<BaseURL>02</BaseURL> - Barmar
正则表达式应该是 <BaseURL>([0-9]+)<\/BaseURL> 以匹配任何数字。 - Barmar
你是在问如何在awk中使用正则表达式的捕获组中的数字来命名“segf”文件吗?请参考https://dev59.com/KGgv5IYBdhLWcg3wBMIK。 - Barmar
我尝试了这个,但仍然看到类似的问题,但现在我能够获得两个文件segment.01和segment.02,但并不是所有的片段URL都保存在这些文件中。awk '

开始写入新的片段文件segment.01等

match($0, /<BaseURL>([0-9]+)/</BaseURL>/, m) { base=m[1] close(segf) segf="segment." base print "将片段写入 " segf print >segf } /<SegmentURL / {print >segf} END {close(segf)} ' mpd
- Raj
这很难读,将其作为问题的更新添加,以便您可以格式化它并易于阅读。 - Barmar
显示剩余3条评论
2个回答

0

这是我的答案

cat dfg | awk 'function writeFile(a) { print $0 >> "File_"a; } BEGIN{FS="[<,>,=]";a=0;}{ if($2 == "BaseURL") { a++;writeFile(a) } else if($2 == "SegmentURL media") { writeFile(a) }}'

解释:- 使用多个文件分隔符进行准确比较和提取所需行,并在获得BaseURL时保持计数器。每次遇到BaseURL时,递增计数器并将其传递给awk中的用户定义函数(每次遇到BaseURL时,打开新文件以写入输出,因为计数器已更改)。

输出:-

File1_4 File1_3 File1_2 File1_1


0
  awk '
# start writing to new segment file segment.01 etc
match($0, /<BaseURL>([0-9]+)\/<\/BaseURL>/, m) {
  base=m[1]
  close(segf)
  segf="segment." base
  print "write segments to " segf
  print >>segf
}
/<SegmentURL / {print >segf}
END {close(segf)}
' mpd

需要使用>>,因为每当遇到新的<BaseURL>时,您都会关闭文件。第一次打开文件后写入,>将清空文件。如果您省略close(segf),我认为它也可以工作。 - Barmar
当我尝试运行上述脚本时,它显示“读取(没有这样的文件或目录)empd”,而我在运行时与mpd文件处于同一目录中,同时我已经为脚本提供了所需的权限(chmod +x run.sh),但我看到以下错误:“读取(没有这样的文件或目录)empd”。 - Raj
看起来错误信息在你的评论中混乱了。 - Barmar
awk命令在脚本中吗?我怀疑你的换行符是CRLF而不是LF,请使用dos2unix修复文件。 - Barmar

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