使用bash shell脚本在2个字符串之间提取字符串

问题描述:

我看过类似这样的问题,但在这种情况下似乎没有任何解决方案可行。我有一个文本文件,它看起来像这样使用bash shell脚本在2个字符串之间提取字符串

START-OF-FILE 
RUNDATE=20140910 
FIRMNAME=dl 
FILETYPE=pc 
REPLYFILENAME=TEST 
DERIVED=yes 
PROGRAMFLAG=oneshot 
SECID=ISIN 
SECMASTER=yes 
PROGRAMNAME=getdata 
START-OF-FIELDS 
ISSUER 
START-OF-DATA 
US345370CN85|0|4|FORD MOTOR COMPANY|FORD MOTOR COMPANY| | | 
US31679BAC46|0|4|FIFTH STREET FINANCE COR|FIFTH STREET FINANCE COR| | | 
END-OF-DATA 
END-OF-FILE 

我试图写一个bash shell脚本只提取“START-OF-DATA”和“END-OF-DATA”排除两者之间的文本这些。所以输出我要找的应该是这样的

US345370CN85|0|4|FORD MOTOR COMPANY|FORD MOTOR COMPANY| | | 
US31679BAC46|0|4|FIFTH STREET FINANCE COR|FIFTH STREET FINANCE COR| | | 

到目前为止,我写的代码看起来像这样

while read line 
do 
    name=$line 

    echo $name | sed -e 's/START-OF-DATA\(.*\)END-OF-DATA/\1/' 

done < $1 

和庆典像

./script.sh file.txt 

那里运行它script.sh是我保存的shell脚本,而file.txt是它读取的文本文件。目前它只读取和回显整个文件。我猜我的语法有点傻。任何在正确的方向指针将不胜感激。 感谢

使用awk你可以这样做:

awk '/START-OF-DATA/{p=1;next} /END-OF-DATA/{p=0;exit} p' file 
US345370CN85|0|4|FORD MOTOR COMPANY|FORD MOTOR COMPANY| | | 
US31679BAC46|0|4|FIFTH STREET FINANCE COR|FIFTH STREET FINANCE COR| | | 

或者使用sed

sed -n '/START-OF-DATA/,/END-OF-DATA/{/START-OF-DATA\|END-OF-DATA/!p;}' file 
US345370CN85|0|4|FORD MOTOR COMPANY|FORD MOTOR COMPANY| | | 
US31679BAC46|0|4|FIFTH STREET FINANCE COR|FIFTH STREET FINANCE COR| | | 
+1

太好了。正是我在找什么......你们很快就掉了标记我必须说:)再次感谢 – tasslebear 2014-09-11 11:47:47

为了使您的解决方案工作,你可以做一个标记,当你点击“START-OF- DATA“读取”True“(或类似),然后在您点击”数据结束“时结束。使用此标记可以指示回显打印标记为“真”(当您位于相关文本块内时)。

...或者你可以使用SED:

sed -n '/START-OF-DATA/,/END-OF-DATA/ { //!p }' file.txt 
+0

感谢您的回复bryn。您的解决方案完美运作由于他的回复速度更快,我不得不赞同@anubhava。不过谢谢。现在脚本工作正常。问候 – tasslebear 2014-09-11 11:52:42

+0

您好bryn。你的[tag:sed]命令行比[anubhava的一个]更好(http://stackoverflow.com/a/25786380/938111)。但对我来说有点神秘:我想知道'{// p}'中的'//'意味着什么。请给出一些解释或链接到网站解释这一点。干杯;-) – olibre 2014-09-12 08:49:56

我想补充Perlish的grep方式,如前所述here

grep -Pzo "(?s)START-OF-DATA.*END-OF-DATA" "$1" 

这仍然包括START-OF-DATAEND-OF-DATA标记。要摆脱他们,该模式有可能成为一个有点不太可读:

grep -Pzo "(?s)(?<=START-OF-DATA\n).*(?=\nEND-OF-DATA)" 

(?<=START-OF-DATA\n)(?=\nEND-OF-DATA)环视断言在perlre描述,即它们用于匹配,但不包括在结果。

+1

不错,使用准备,但是行开始数据和数据结束被打印:/请尝试改进你的命令行,以避免打印这两行。玩得开心:-)干杯 – olibre 2014-09-11 12:29:07

+1

@olibre:感谢您指出。我添加了改进的命令行。 – 2014-09-11 16:53:25