使用 AWK 提取以 *** 分隔的段落

JoV*_*oVe 4 shell grep sed awk text-processing

我有一个像下面这样的文件:

blablabla
blablabla
***
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3

blablabla
blablabla
Run Code Online (Sandbox Code Playgroud)

我想用thingsIwantToRead. 当我不得不处理这样的问题时,我是这样使用AWK的

awk 'BEGIN{ FS="Separator above the paragraph"; RS="" } {print $2}' $file.txt | awk 'BEGIN{ FS="separator below the paragraph"; RS="" } {print $1}'
Run Code Online (Sandbox Code Playgroud)

它奏效了。

在这种情况下,我尝试放置FS="***", "\*{3}", "\*\*" (它不起作用,因为 AWK 将其视为普通星号),"\\*\\*"或者我能想到的任何正则表达式,但它不起作用(它不打印任何内容)。

你知道为什么吗?

如果没有,你知道另一种方法来处理我的问题吗?

在我要解析的文件的摘录下方:

13.2000000000     , 3*0.00000000000       ,  11.6500000000     , 3*0.00000000000       ,  17.8800000000

Blablabla

  SATELLITE EPHEMERIS
     ===================
Output frame: Mean of J2000

       Epoch                  A            E            I           RA           AofP          TA      Flight Ang
*****************************************************************************************************************
2012/10/01 00:00:00.000     6998.239     0.001233     97.95558     77.41733     89.98551    290.75808    359.93398
2012/10/01 00:05:00.000     6993.163     0.001168     97.95869     77.41920    124.72698    274.57362    359.93327
2012/10/01 00:10:00.000     6987.347     0.001004     97.96219     77.42327    170.94020    246.92395    359.94706
2012/10/01 00:15:00.000     6983.173     0.000893     97.96468     77.42930    224.76158    211.67042    359.97311
 <np>
 ----------------
 Predicted Orbit:
 ----------------

 Blablabla
Run Code Online (Sandbox Code Playgroud)

我想提取:

2012/10/01 00:00:00.000     6998.239     0.001233     97.95558     77.41733     89.98551    290.75808    359.93398
2012/10/01 00:05:00.000     6993.163     0.001168     97.95869     77.41920    124.72698    274.57362    359.93327
2012/10/01 00:10:00.000     6987.347     0.001004     97.96219     77.42327    170.94020    246.92395    359.94706
2012/10/01 00:15:00.000     6983.173     0.000893     97.96468     77.42930    224.76158    211.67042    359.97311
Run Code Online (Sandbox Code Playgroud)

我试图用来获取 * 行后的数字的命令:

`awk 'BEGIN{ FS="\\*{2,}"; RS="" } {print $2}' file | awk 'BEGIN{ FS="<np>"; RS="" } {print $1}'`
Run Code Online (Sandbox Code Playgroud)

ter*_*don 8

告诉 awk 在两个分隔符之间打印。具体来说:

awk '/\*{4,}/,/<np>/' file
Run Code Online (Sandbox Code Playgroud)

这也将打印包含分隔符的行,因此您可以使用以下命令删除它们:

awk '/\*{4,}/,/<np>/' file | tail -n +2 | head -n -1
Run Code Online (Sandbox Code Playgroud)

或者,如果一行与第一个分隔符匹配,则可以将变量设置为 true,当它与第二个分隔符匹配时设置为 false,并且仅在为 true 时才打印:

awk '/\*{4,}/{a=1; next}/<np>/{a=0}(a==1){print}' file
Run Code Online (Sandbox Code Playgroud)

a如果当前行匹配 4 个或更多*,则上面的命令将设置为 1,并且也会跳到该next行。这意味着***永远不会打印该行。


这是对最初的、被误解的问题版本的回答。我把它留在这里是因为它在稍微不同的情况下很有用。

首先,你不想要FS(字段分隔符),你想要RS(记录分隔符)。然后,要传递一个文字*,您需要对其进行两次转义。一次转义 the *,一次转义反斜杠(否则,awk 将尝试以与\ror相同的方式匹配它\t)。然后,打印第二个“行”:

$ awk -vRS='\\*\\*\\*' 'NR==2' file

thingsIwantToRead1   
thingsIwantToRead2   
thingsIwantToRead3  
Run Code Online (Sandbox Code Playgroud)

为避免输出周围出现空行,请使用:

$ awk -vRS='\n\\*\\*\\*\n' 'NR==2' file
thingsIwantToRead1   
thingsIwantToRead2   
thingsIwantToRead3  
Run Code Online (Sandbox Code Playgroud)

请注意,这假定***每个段落之后,而不仅仅是在您显示的第一个之后。


fre*_*ini 6

除了@terdon 的回答之外,使用 awk(和 sed),您还可以使用范围模式:

awk '/sep1/,/sep2/{print}' file
Run Code Online (Sandbox Code Playgroud)

或者

sed -n '/sep1/,/sep2/p' file
Run Code Online (Sandbox Code Playgroud)

将打印所有内容(包括)sep1sep2. 那是:

~$ awk '/sep1/,/sep2/{print}' file
sep1
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
sep2
Run Code Online (Sandbox Code Playgroud)

在你的情况下:

~$ awk '/\*\*\*/,/^$/{print}' file
***
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
 
Run Code Online (Sandbox Code Playgroud)

然后您可能想要删除第一行和最后一行。

例如:

~$ sed -n '/\*\*\*/,/^$/p' file | sed '1d;$d'
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
Run Code Online (Sandbox Code Playgroud)

或者

~$ awk '/\*\*\*/,/^$/{print}' file | awk 'NR>1&&!/^$/ {print}'
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
Run Code Online (Sandbox Code Playgroud)

如果你的段落不是太长。