【问题标题】:Is this text extraction scenario possible in linux bash shell?这种文本提取场景在 linux bash shell 中是否可行?
【发布时间】:2014-08-19 22:51:53
【问题描述】:

假设我的文本文件是这样的

人物 1:电影 1
(空格和制表符):电影 2
(空格和制表符):电影 3
(空格和制表符):电影 4

我想为某部电影寻找演员。 所以这就是我要做的事情。

做一个 grep 猫演员 | grep 'movie3'

这将给我第 3 行,这是一个空行,出现 unitl 电影 3。因此,如果我能以某种方式获得遵循此模式的特定行之前的第一行

grep '^[^ \t].'(不以空格开头)

它必须是这部电影中演员的名字。(我不在乎那里的电影)

是否有任何 sed/grep/awk 组合可以帮助我在 shell 中执行此操作?我希望问题很清楚。

【问题讨论】:

    标签: regex bash sed grep


    【解决方案1】:

    这有点晦涩,但完成工作:

    awk '/^[^ ]/{p=0} /Person1/{p=1} p'
    

    例子:

    输入文件:

    Person1 : movie1
        : movie 2
        : movie 3
        : movie 4
    Person2 : movie 5
        : movie 6
    

    执行:

    awk '/^[^ ]/{p=0} /Person1/{p=1} p' file
    Person1 : movie1
        : movie 2
        : movie 3
        : movie 4
    
    awk '/^[^ ]/{p=0} /Person2/{p=1} p' file
    Person2 : movie 5
        : movie 6
    

    OBS: 在命令行中,输出是缩进的。

    解释:

    1. 如果行不以空格开头,则设置 p=0
    2. 如果该行包含 Person1 设置 p=1
    3. 如果 p=1 则打印(这部分是模糊的)

    也可以在perl完成:

    perl -ne '/^\w+/ && {$p=0}; /Person1/ && {$p=1}; $p && {print}' 
    

    【讨论】:

      【解决方案2】:

      这可能对你有用(GNU sed):

      sed -n '/^\S/h;/movie 3/{H;x;s/:.*:/:/p}' file
      

      使用-n 开关提供类似grep 的特性。将人保存在保留空间中并将电影附加到其中。然后删除不需要的文本并打印出来。

      【讨论】:

        【解决方案3】:

        如果我能正确理解问题,我会用 awk 来做:

         awk -F: -v s="$search" '$1~/\S/{p=$1}$2~s{print $1 FS $2}' file
        

        movie 3测试:

        kent$ cat f
        Person1 : movie1
                  : movie 2
                  : movie 3
                  : movie 4
        

        在上面的文件中,有前导空格/制表符

        kent$  awk -F: -v s="movie 3" '$1~/\S/{p=$1}$2~s{print p FS $2}' f
        Person1 : movie 3
        

        【讨论】:

        • 我创建了一个和你一样的文件,在 person1:movie1 的行中没有前导空格。我运行了你给我的确切命令。它只给出了这个,(行首):movie 3.
        • 我在 linux 上。如果您在 mac 上运行它,它应该可以在那里工作?
        • @Dude 我只有 linux。我猜是因为你的 gawk 版本比我的低,你可以试试:awk ... '$1~/[^ \t]/{....}'
        • 是的,它奏效了。如果您不介意,请您简要解释一下正则表达式。
        • @Dude 正则表达式只是匹配一个字符串($1,第一列),如果它包含任何非空字符。像这样的问题是 awk 的典型问题。 grep 很棒,但在这里它不是正确的工具。(我的观点)
        【解决方案4】:

        Bill Murray 土拨鼠日

        这有点棘手,但你可以使用这个:

        grep -P "(?sm)^\S+[^:\r\n]*?(?=\s*:(?:(?!^\S).)*?Groundhog Day)" mymoviefile
        

        demo

        • -P 激活 Perl 模式
        • (?sm) 开启两个模式修饰符:
        • s 激活 DOTALL 模式,允许点跨行匹配
        • m 开启多行模式,允许^$ 在每一行上匹配
        • ^ 锚断言我们位于行首
        • \S+ 匹配一个或多个非空格字符
        • [^:\r\n]*? 懒惰地匹配任何非冒号、非换行符,最多...
        • 前瞻 (?=\s*:(?:(?!^\S).)*?Groundhog Day) 可以在不消耗字符的情况下断言以下内容是...
        • \s*: 可选空格和冒号
        • 然后(?:(?!^\S).)* 零个或多个不是非空格字符的字符在行首,延迟匹配到...
        • Groundhog Day电影名!

        参考

        【讨论】:

        • 我尝试运行它。它不起作用。这是错误消息 grep: unrecognized character after (? or (?-. 我正在尝试调试它,但由于它非常复杂,而且我不知道你在这里使用的一半东西,我想我会的需要你的进一步帮助。:^D
        • 添加了tweak和tweak,看看。 :)
        • 感谢您的帮助。但绝对不适合胆小的人。
        • 解释完毕。 `这绝对不适合胆小的人` 你是对的,这远非显而易见,但通过解释我相信你会理解它。有效吗?
        • 谢谢,伙计,很高兴它有帮助! :)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-24
        • 2010-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-02
        相关资源
        最近更新 更多