如何编写sed脚本来从文本文件中grep信息

我试图做我的作业,只限于使用sed过滤input文件到一定格式的输出。 这里是input文件(命名stocks ):

 Symbol;Name;Volume ================================================ BAC;Bank of America Corporation Com;238,059,612 CSCO;Cisco Systems, Inc.;28,159,455 INTC;Intel Corporation;22,501,784 MSFT;Microsoft Corporation;23,363,118 VZ;Verizon Communications Inc. Com;5,744,385 KO;Coca-Cola Company (The) Common;3,752,569 MMM;3M Company Common Stock;1,660,453 ================================================ 

输出需要是:

 BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

我确实想出了一个解决scheme,但效率不高。 这是我的sed脚本(命名为try.sed ):

 /.*;.*;[0-9].*/ { N N N N N N s/\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*/\1, \2, \3, \4, \5, \6, \7/gp } 

我在shell上运行的命令是:

 $ sed -nf try.sed stocks 

我的问题是,是否有更好的方式使用sed获得相同的结果? 我写的脚本只能处理7行数据。 如果数据更长,我需要重新修改我的脚本。 我不知道如何让它更好,所以我在这里寻求帮助!

感谢您的任何build议。

还有一种使用sed

 sed -ne '/^====/,/^====/ { /;/ { s/;.*$// ; H } }; $ { g ; s/\n// ; s/\n/, /g ; p }' stocks 

输出:

 BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

说明:

 -ne # Process each input line without printing and execute next commands... /^====/,/^====/ # For all lines between these... { /;/ # If line has a semicolon... { s/;.*$// # Remove characters from first semicolon until end of line. H # Append content to 'hold space'. } }; $ # In last input line... { g # Copy content of 'hold space' to 'pattern space' to work with it. s/\n// # Remove first newline character. s/\n/, /g # substitute the rest with output separator, comma in this case. p # Print to output. 

编辑:我编辑了我的算法,因为我忽略了考虑页眉和页脚(我以为他们只是为了我们的利益)。

sed根据其设计访问输入文件的每一行,然后对符合某个规范(或没有)的表达式执行表达式。 如果你正在剪裁你的脚本到一定数量的行,你肯定是做错了! 我不会给你写一个脚本,因为这是作业,但是一个方法的总体思路是编写一个脚本来完成以下工作。 把顺序看作是脚本中的顺序。

  1. d跳过前三行,删除模式空间,然后立即移动到下一行。
  2. 对于不是空白行的每一行,请执行以下步骤。 (这将全部放在一组大括号中。)
    1. s (替换)命令替换包括第一个分号( ; )在内的所有内容,并用逗号和空格(“,”)替换。
    2. 追加当前的模式空间到保持缓冲区 (看H )。
    3. 删除模式空间并移至下一行,如步骤1中所示。
  3. 对于脚本中的每一行(应该是第一个空行),将保留空间的内容检索到模式空间中。 (这将在上面的花括号之后。)
  4. 用空格替换模式空间中的所有换行符。
  5. 接下来,用空格替换模式空间中的最后一个逗号和空格。
  6. 最后,退出程序,以便不再处理更多行。 我的脚本没有这个工作,但我不是100%确定为什么。

这就是说,这只是一个方法去做。 sed经常提供不同的复杂方式来完成任务。 我用这种方法写的解决方案是10行。

作为一个说明,我不打扰抑制打印(与-n )或手动打印(与p ); 每行都默认打印。 我的脚本像这样运行:

 $ sed -f companies.sed companies BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

这个sed命令应该产生你需要的输出:

 sed -rn '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt 

或在Mac上:

 sed -En '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt 

这可能适合你:

 sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stocks 
  • 我们不想标题,所以让我们删除它们。 1d
  • 所有的数据项都由…分隔; 所以让我们专注于这些线路。 /;/
  • 上面的东西从第一个删除了所有东西; 到行的末尾,然后把它放在保持空间(HS) {s/;.*//;H}
  • 当你到达最后一行时,使用g命令用HS覆盖它,删除第一个换行符(由H命令生成),用逗号和空格替换所有后续换行符,并打印剩下的内容。 ${g;s/.//;s/\n/, /g;q}
  • 删除一切d

下面是一个终端会话,展示了构建sed命令的增量细化:

 cat <<! >stock # paste the file into a here doc and pass it on to a file > Symbol;Name;Volume > ================================================ > > BAC;Bank of America Corporation Com;238,059,612 > CSCO;Cisco Systems, Inc.;28,159,455 > INTC;Intel Corporation;22,501,784 > MSFT;Microsoft Corporation;23,363,118 > VZ;Verizon Communications Inc. Com;5,744,385 > KO;Coca-Cola Company (The) Common;3,752,569 > MMM;3M Company Common Stock;1,660,453 > > ================================================ > ! sed '1d;/;/!d' stock # delete headings and everything but data lines BAC;Bank of America Corporation Com;238,059,612 CSCO;Cisco Systems, Inc.;28,159,455 INTC;Intel Corporation;22,501,784 MSFT;Microsoft Corporation;23,363,118 VZ;Verizon Communications Inc. Com;5,744,385 KO;Coca-Cola Company (The) Common;3,752,569 MMM;3M Company Common Stock;1,660,453 sed '1d;/;/{s/;.*//p};d' stock # delete all non essential data BAC CSCO INTC MSFT VZ KO MMM sed '1d;/;/{s/;.*//;H};${g;l};d' stock # use the l command to see what's really there! \nBAC\nCSCO\nINTC\nMSFT\nVZ\nKO\nMMM$ sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;l};d' stock # refine refine BAC, CSCO, INTC, MSFT, VZ, KO, MMM$ sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stock # all done! BAC, CSCO, INTC, MSFT, VZ, KO, MMM