2012-02-03 29 views
6

我试图做我的家庭作业仅限于使用sed过滤输入文件输出的某种格式的grep信息。这里是输入文件(名为stocks):我怎样写sed脚本从文本文件

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 

,但它的效率不高。这里是我的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行数据。如果数据更长,我需要重新修改我的脚本。我不知道如何让它更好,所以我在这里寻求帮助!

感谢您的任何建议。

+5

+1承认这是功课和野生'S/\( 。* \); ...... /'你放进去的东西!祝你好运。 – shellter 2012-02-03 19:04:31

回答

2

使用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. 
+0

哇,谢谢比雷! 我不知道我可以做双{},我忘了我可以使用替代w/o g命令来匹配第一次出现的比赛。 我还有几个问题在这里。 1.为什么最后一个块位于最后一行模式($)? 2.对于新行的第二个替换。其目的是删除空行吗? 2.对于新行的最后一个替换,在“MMM”之后它怎么没有替换换行符? 你给了我一个很好的解释,但我仍然不明白$ {}的用途。希望你能帮助我更多地理解它。非常感谢你的帮助!! – Jaycee 2012-02-03 22:22:17

+0

@Jaycee:[1]在文件处理过程中,我将所需的字符串保存在'保留空间'中,并且只在最后一行恢复该内容,修改并打印。 [2]'H'命令将'\ n'加上'模式空间'的内容加到'保留空间',所以最后一行的内容就像'\ nBAC \ nCSCO \ nINTC \ nMSFT \ nVZ \ nKO \ nMMM '。然后我删除第一个'\ n'并用''替换其余的',' – Birei 2012-02-03 22:41:41

+0

啊......我现在明白了!非常感谢!!!!!使用H和g很酷...... =)不知道为什么我的老师没有教我们这些命令。再次感谢你!!!!!^O ^ – Jaycee 2012-02-03 22:51:17

0

这个sed命令应该出示您所需的输出:

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

或Mac上:

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

这是作业。你真的不应该只是给他一个答案。 – 2012-02-03 18:50:06

+0

亲爱的anubhava,我已经运行了你的命令,但输出不在一行。其中一个挑战是将所有换行符替换为除逗号和最后一行之外的1个空格。最后一个之后不应该有逗号。 – Jaycee 2012-02-03 18:59:42

+0

是的,我的脚本的行为与grep -o完全相同,因为现在我意识到它的作业,我会将其余脚本留给您。 – anubhava 2012-02-03 19:39:06

2

编辑:我已经编辑我的算法,因为我忘了把考虑头和页脚(我认为它们只是为了我们的利益)。

sed,通过其设计,访问一个输入文件的每行,然后进行在符合一些规范(或无)那些表达式。如果你正在将你的脚本剪裁成一定数量的行,你肯定会做错事!我不会给你写一个脚本,因为这是作业,但是一种解决这个问题的总体思路是编写一个脚本来完成以下工作。按照事物在脚本中的顺序考虑排序。

  1. 使用d跳过前三行,删除模式空间并立即移至下一行。
  2. 对于每个不是空白线线,执行下列步骤。 (这将全部位于一组大括号中。)
    1. 使用s(替换)命令替换包含第一个分号(;)和逗号和空格(“,”)的所有内容。
    2. 追加当前模式空间到hold buffer(看H)。
    3. 删除模式空间和在步骤1
  3. 对于每个到达这点在脚本行移动到下一行,比如(应该是第一个空行),检索的内容把握空间进入图案空间。 (这将是大括号后的上方。)
  4. 替代所有换行符在什么模式空间。
  5. 接下来,用空格替换模式空间中的最后一个逗号和空格。
  6. 最后,退出程序,以便不再处理更多行。我的脚本没有这个工作,但我不是100%确定为什么。

这就是说,这只是一个方法去解决它。 sed通常提供不同的复杂方式来完成任务。我用这种方法写的解决方案是10行。作为一个说明,我不打扰抑制打印(使用-n)或手动打印(使用p);我不打扰抑制打印(使用-n)或手动打印(使用p);我不打扰抑制打印(使用-n)或手动打印(使用p);每行都默认打印。我的脚本运行是这样的:

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

@Jaycee上面哪个部分是你遇到的麻烦?如果可以的话,我想提高我的解释! – 2012-02-03 19:44:21

+0

嗨,丹,谢谢你的提示。对于第一步,我会用逗号和空格来显示所有符号。但是我很难做第二步。我如何获得不是最后一行的每一行?从技术上讲,MMM并不是最后一条线。 ============是最后一行。我很困惑,真的不知道如何继续。你能否详细说明一下?非常感谢你的帮助! – Jaycee 2012-02-03 19:50:28

+0

我可以得到最后一个如下: /[0-9] $/{N N s/\(。* \);。*;。* \ n \ n \ = */\ 1/GP } – Jaycee 2012-02-03 19:51:50

0

这可能会为你工作:

sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stocks 
  • 我们不希望的标题让我们将它们删除。 1d
  • 所有的数据项都由;分隔,所以让我们专注于这些线。 /;/
  • 的东西上面删除一切从第一;到行的末尾,然后塞到走在保持空间(HS){s/;.*//;H}
  • 当你到最后一行,与HS使用覆盖它g命令,删除第一个换行符(由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