【问题标题】:AWK or sed way to paste non-adjacent linesAWK 或 sed 方式粘贴不相邻的行
【发布时间】:2016-08-28 03:52:55
【问题描述】:
$ cat file
aaa bbb ccc
ddd eee
jjj kkk lll
mmm
nnn ooo ppp

下面的 AWK 命令会将 'mmm' 行粘贴到 'ddd eee' 行的末尾。有没有更简单的方法可以使用 AWK 或 sed 来做到这一点?

$ awk 'FNR==NR {if (NR==4) foo=$0; next} FNR==2 {print $0" "foo; next} FNR==4 {next} 1' file file
aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp

澄清一下:我想在这个特定文件的第 2 行末尾粘贴第 4 行,在“ddd eee”和“mmm”之间有一个空格。这就是任务。有没有比我想出的更简单的 AWK 或 sed 解决方案?

【问题讨论】:

  • 您如何知道何时需要mmm 行?你怎么知道它什么时候会出现?您是否试图确保每行出现相同数量的单词?单词的数量总是三个吗?如果该行包含mmm zzz 而不仅仅是mmm,会发生什么?如果最后有几行带有tttuuu 怎么办?应该有ddd eee tttmmm zzz uuu 吗? ETC?到目前为止,这个问题的具体化程度严重不足,因此无法明智地回答。

标签: awk sed


【解决方案1】:

这可以在sed 中使用保持空间来完成:

sed '2{N;h;N;s/\n.*\n/ /;p;g;D;}' file
  • 2{...} 在第二行运行随附的命令。
  • N;h;N 将下两行读入模式空间,保留前两行。
  • s/\n.*\n/ / 用空格代替中间线。
  • p;g;D 打印粘贴的行,加载hold space,删除 第一行(留下前一个替代者删除的行)。

或使用捕获(\(...\))和反向引用(\1\2 等):

sed '2{N;N;s/\(\n.*\)\n\(.*\)/ \2\1/;}' file
  • 2{...} 在第二行运行随附的命令。
  • N;N 将接下来的两行读入模式空间。
  • s/\(\n.*\)\n\(.*\)/ \2\1/ 交换第三行和第四行,连接第一行和第三行。
    • \(\n.*\) 捕获第三行,包括前导换行。
    • \n\(.*\) 捕获第四行,不包括前导换行符。
    • / \2\1/ 将匹配的部分(第三和第四行)替换为空格,然后是第二个,然后是第一个捕获组。

【讨论】:

  • 第二个版本很不错。我有 GNU sed,所以这有效: sed -r '2{N;N;s/(\n.*)\n(.*)/ \2\1/;}' file
  • 你不能认真地认为这比你开始的脚本更简单???请记住,您要求更简单,而不是更简洁。
【解决方案2】:

这符合修改后的问题陈述的字母——它打印第 1 行,在第 2 行的内容之后附加第 4 行作为第 2 行,然后打印第 3 行,然后打印第 5 行及以后:

awk 'NR == 1 || NR >= 5 { print; next }
     NR == 2 { save2 = $0 }
     NR == 3 { save3 = $0 }
     NR == 4 { print save2, $0; print save3 }' file

它比问题中的代码更简单,因为它只扫描文件一次。

输出:

aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp

【讨论】:

  • simpler 这个词很有趣。我发现这并不比两次解析文件更简单(更有效,是的,但更简单,不是),我发现accepted answer of sed runes 要复杂得多。我猜simpler 在旁观者的眼中......
  • 问题陈述使大多数关于解决方案优点的讨论变得无关紧要。这是一组糟糕的(奇怪的,完全不通用的)要求。 XY Problem 可能被过度简化(MCVE 太多了)。正如你所说,简单是旁观者的眼中。您的解决方案更紧凑;我不觉得它更简单。
  • 我同意,要求不明确,我理解,旁观者的眼睛。对我来说,当您谈论要求代码“简单”时,它必须考虑易于维护/增强,因为如果您永远不会再看它,谁会在乎它有多“简单”。在这种情况下,如果将来我们不得不合并第 20 行和第 40 行而不是第 2 行和第 4 行。使用 OP 最初发布的 2-pass 解决方案和我发布的修改版本,您只需将数字 2 更改为 20 和4 到 40,而你的和 sed 解决方案需要大量添加代码或重写。
【解决方案3】:

TXR中的解决方案:

$ txr -c '@line1
@line2
@line3
@line4
@(data rest)
@(output)
@line1
@line2 @line4
@line3
@  (repeat)
@  rest
@  (end)
@(end)' file
aaa bbb ccc
ddd eee mmm
jjj kkk lll
nnn ooo ppp

【讨论】:

    【解决方案4】:

    这个比较简单:

    $ awk 'FNR==NR {if (NR==4) foo=$0; next} FNR==2{$0=$0" "foo} FNR!=4' file file
    aaa bbb ccc
    ddd eee mmm
    jjj kkk lll
    nnn ooo ppp
    

    其他解决方案可能更快或使用更少的内存,但不会更简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-10
      • 2017-04-23
      • 2018-08-21
      • 2010-10-20
      • 1970-01-01
      • 2011-01-23
      • 2012-02-10
      • 2019-08-31
      相关资源
      最近更新 更多