【问题标题】:Using command line to remove text?使用命令行删除文本?
【发布时间】:2014-08-07 21:47:53
【问题描述】:

我有一个包含遵循这种格式的行的大文件:

New-England-Center-For-Children-L0000392290
Southboro-Housing-Authority-L0000392464
Crew-Star-Inc-L0000391998
Saxony-Ii-Barber-Shop-L0000392491
Test-L0000392334

我想要做的就是把它缩小到这个:

New-England-Center-For-Children
Southboro-Housing-Authority
Crew-Star-Inc
Test

有人可以帮忙吗?

【问题讨论】:

    标签: perl shell text command-line


    【解决方案1】:

    使用 GNU awk

    awk -F\- 'NF--' OFS=\- file
    New-England-Center-For-Children
    Southboro-Housing-Authority
    Crew-Star-Inc
    Saxony-Ii-Barber-Shop
    Test
    
    • 将输入和输出字段分隔符设置为-
    • NF 包含字段数。将其减 1 以删除最后一个字段。

    使用sed

    sed 's/\(.*\)-.*/\1/' file
    New-England-Center-For-Children
    Southboro-Housing-Authority
    Crew-Star-Inc
    Saxony-Ii-Barber-Shop
    Test
    
    • 简单的贪婪正则表达式匹配最后一个连字符。
    • 替换使用捕获的组并丢弃其余组。

    【讨论】:

    • 好,我特别喜欢 sed 解决方案。非常整洁清晰!
    【解决方案2】:

    问题的第 1 版

    输入的第一个版本是 HTML 形式,在所需文本之前和之后都必须删除部分:

    $ sed -r 's|.*[A-Z]/([a-zA-Z-]+)-L0.*|\1|' input
    Special-Restaurant
    Eliot-Cleaning
    Kennedy-Plumbing
    

    问题的第 2 版

    修改后的问题,只需要去掉-L00开头的文字即可:

    $ sed 's|-L00.*||' input2
    New-England-Center-For-Children
    Southboro-Housing-Authority
    Crew-Star-Inc
    Saxony-Ii-Barber-Shop
    Test
    

    这两个命令都使用一个“替代”命令。该命令的格式为s|old|new|

    【讨论】:

      【解决方案3】:

      perl 代码为:perl -nle'print $1 if(m{-.*?/(.*?-.*?)-})

      我们可以将正则表达式分解为匹配以下内容:

      • - 在城市和州之间
      • .*? 匹配使正则表达式工作的最小字符集,即状态
      • / 匹配状态和你想要的数据之间的斜线
      • ( 开始捕获您感兴趣的数据
      • .*?-.*? 将匹配您关心的数据
      • ) 将关闭捕获
      • - 将匹配 L####### 之前的破折号,以在您的数据之后为正则表达式提供匹配的内容。这将防止最小的正则表达式匹配 0 个字符。

      然后 print 语句将打印出捕获的内容(您的数据)。

      【讨论】:

        【解决方案4】:

        awk 喜欢这些东西:

        $ awk -F[/-] -v OFS="-" '{print $(NF-3), $(NF-2)}' file
        Special-Restaurant
        Eliot-Cleaning
        Kennedy-Plumbing
        

        这会将/- 设置为可能的字段分隔符。基于它们,它打印由分隔符 - 分隔的 last_field-3 和 last_field-2。注意$NF 代表最后一个参数,因此$(NF-1) 是倒数第二个,依此类推。


        这个sed 也很有帮助:

        $ sed -r 's#.*/(\w*-\w*)-\w*\.\w*</loc>$#\1#' file
        Special-Restaurant
        Eliot-Cleaning
        Kennedy-Plumbing
        

        它在斜线/ 之后选择块word-word,然后是word.word&lt;/loc&gt; + end_of_line。然后,它打印回这个块。


        更新

        根据您的新输入,可以这样做:

        $ sed -r 's/(.*)-L\w*$/\1/' file
        New-England-Center-For-Children
        Southboro-Housing-Authority
        Crew-Star-Inc
        Saxony-Ii-Barber-Shop
        Test
        

        它选择块 -L + 一些东西 + 行尾的所有内容,并将其打印回来。

        你还可以使用另一个技巧:

        rev file | cut -d- -f2- | rev
        

        因为你想要的是- 分隔字段的每一片,所以让我们得到所有这些,但最后一个。如何?通过反转线路,从第 2 条线路中获取所有线路,然后反转。

        【讨论】:

        • 感谢所有帮助!如果名称也类似于“Test-Test-Test-Test”,这会起作用吗?
        • 嗯,我不知道。您最好更新您的问题,指出您要处理的各种行,因为我写的答案是基于它们。
        • 我刚刚更新了问题,实际上我能够缩小范围,让你更容易:)
        • @user3918845 好的!现在看起来确实更容易了 :) 刚刚更新了两种方法。
        • @fedorqui:我认为,总的来说,我们是一致的。没有其他不赞成“在类似情况下”
        【解决方案5】:

        下面是我使用 Perl 的方法:

        perl -nle 'm{example[.]com/bp/(.*?)/(.*?)-L\d+[.]htm} && print $2' filename
        

        注意:原来的问题是这样匹配输入行的:

        <loc>http://www.example.com/bp/Lowell-MA/Special-Restaurant-L0000423916.htm</loc>
        <loc>http://www.example.com/bp/Houston-TX/Eliot-Cleaning-L0000422797.htm</loc>
        <loc>http://www.example.com/bp/New-Orleans-LA/Kennedy-Plumbing-L0000423121.htm</loc>
        

        -n 选项告诉 Perl 循环遍历文件的每一行(但不打印出来)。

        -l 选项在每个打印的末尾添加一个换行符

        -e 'perl-code' 选项为每一行输入执行perl-code

        图案:

        /regex/ && print
        

        仅当正则表达式匹配时才会打印。如果正则表达式包含捕获括号,您可以将第一个捕获的部分称为 $1,将第二个捕获的部分称为 $2,依此类推。

        如果您的正则表达式包含斜杠,则使用不同的正则表达式分隔符可能更清晰(“m”代表“匹配”):

        m{regex} && print
        

        如果您有现代 Perl,您可以使用 -E 启用现代功能并使用 say 而不是 print 来打印附加换行符:

        perl -nE 'm{example[.]com/bp/(.*?)/(.*?)-L\d+[.]htm} && say $2' filename
        

        【讨论】:

          【解决方案6】:

          这在 Perl 中非常简洁

          perl -i.bak -lpe's/-[^-]+$//' myfile
          

          请注意,这将修改输入文件就地,但会将原始数据的备份保存在名为myfile.bak

          【讨论】:

            猜你喜欢
            • 2014-01-13
            • 2013-10-14
            • 1970-01-01
            • 2015-09-07
            • 1970-01-01
            • 2012-10-14
            • 2011-01-29
            • 2018-04-09
            相关资源
            最近更新 更多