【问题标题】:move line which matches pattern to previous line将匹配模式的行移动到上一行
【发布时间】:2021-04-22 06:30:30
【问题描述】:

我有一个结构文件

12312
desc: bleh...
9938
desc: blah...
desc: bloh...
desc: blih...
desc: bluh...
9912
desc: blah...

我想将匹配模式“desc:”的行移到上一行或删除每个模式“desc:”之前的行中的'\n'。

想要的输出:

12312 desc: bleh...
9938 desc: blah... desc: bloh... desc: blih... desc: bluh... 
9912 desc: blah...

我试过了

awk '!/desc:/{
 printf "%s ",$0
 getline
 printf "%s \n",$0
}
/desc/{print}' file

没有结果。

其实所有的数据都是awk -F\" '{print $4 "\t" $6}'的输出 也许我可以先做点什么?

【问题讨论】:

  • 无法得到它:desc: blah... 不匹配 9912,但它会移动到它。你能澄清你的问题吗?
  • 我想将匹配模式 "desc:" 的行移到上一行或删除每个模式 "desc:" 之前的行中的 '\n'。
  • 使用 getline 通常是错误的方法,在这种情况下肯定是这样。在您阅读 awk.info/?tip/getline 并完全理解所有注意事项之前,不要考虑使用 getline。

标签: bash sed awk


【解决方案1】:

sedoneliner

sed ':a $!N;s/\ndesc/ desc/;ta P;D'

会输出

12312 desc: bleh...
9938 desc: blah... desc: bloh... desc: blih... desc: bluh...
9912 desc: blah...

【讨论】:

    【解决方案2】:

    awk 的一种方式:

    $ awk '!/^desc:/&&NR>1{print OFS}{printf "%s ",$0}END{print OFS}' file
    12312 desc: bleh...
    9938 desc: blah... desc: bloh... desc: blih... desc: bluh...
    9912 desc: blah...
    

    说明:

    • !/^desc:/ 匹配不以 desc: 开头的行,不包括文件 NR>1 中的第一行。
    • {print OFS} 在匹配行之前打印输出字段分隔符。在awk 中,默认OFS\n
    • {printf "%s ",$0} 打印没有尾随换行符的每一行。
    • END{print OFS} 在文件被读取后添加一个尾随换行符。

    现场演示:http://ideone.com/ajH14u

    【讨论】:

    • 你不能解释一下。我没有得到同样的结果。实际上所有数据都是awk -F\" '{print $4 "\t" $6}'的输出
    • @IgorVoltaic 我已经添加了解释。只要数据采用问题中描述的格式,数据来自哪里都可以。说你没有得到相同的结果是没有帮助的。
    • END{print OFS} 将在每行末尾添加一个空格,使用 END{print ""} 仅打印一个换行符。您还通过使用 printf "%s ",$0 而不是 printf " %s",$0 在每行末尾添加第二个空格,但您需要重新考虑脚本逻辑来解决这个问题。
    【解决方案3】:
    $ cat file
    12312
    desc: bleh...
    9938
    desc: blah...
    desc: bloh...
    desc: blih...
    desc: bluh...
    9912
    desc: blah...
    
    $ awk '{printf "%s%s",(/^desc:/?OFS:ors),$0; ors=ORS} END{print ""}' file
    12312 desc: bleh...
    9938 desc: blah... desc: bloh... desc: blih... desc: bluh...
    9912 desc: blah...
    

    【讨论】:

    • @Jaypal - 这是处理连接线的常见 awk 方式。您要么需要打印 ORS(如果它是输入中的第一行,则不需要打印)或 OFS 在每行之前基于它是块中的第一行还是后续行,因此您只需使用三元表达式来捕获条件区分块中的第一行和后续行。
    • 没错,只是在printf 内部使用ternary operator 非常棒。
    【解决方案4】:

    Perl 解决方案:

    perl -pe 's/\n/ /; ! /^desc:/ and print "\n" unless 1 == $.' FILE
    

    【讨论】:

    • 使用print "\n" unless 1 == $. || /^desc:/不是更直观吗?
    • 我假设! /^desc:/ and print "\n" unless 1 == $. 的意思是if desc is not found then print a newline unless there's one only field on the line。这是一个非常讨厌的陈述,因为它至少有几个负面因素。没有更清晰的写法吗?我在评论中看到了print "\n" unless 1 == $. || /^desc:/ 的建议,但你不能在 perl 中写一些像if ($. > 1 || /^desc:/) print "\n" 这样简单明了的东西吗?我什至不知道这是否正确解释了原始 perl 意图。
    • 嗯,这说明了我是如何到达那里的:我从and 开始,注意到开头的空行,所以添加了unless
    【解决方案5】:

    使用

    script.vim的内容:

    set backup
    g/\v^desc/ normal kJ
    saveas! output.txt
    q!
    

    像这样运行它:

    vim -u NONE -N -S script.vim infile
    

    它会创建一个带有内容的output.txt文件:

    12312 desc: bleh...
    9938 desc: blah...  desc: bloh...  desc: blih...  desc: bluh...
    9912 desc: blah...
    

    【讨论】:

      【解决方案6】:

      使用“新”GNU 选项-z,您可以使用

      | sed -z 's/\ndesc:/ desc:/g'
      

      【讨论】:

        猜你喜欢
        • 2014-08-19
        • 2013-10-28
        • 1970-01-01
        • 1970-01-01
        • 2021-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多