【问题标题】:Join current and next line, then the next line and its successor using sed使用 sed 加入当前行和下一行,然后是下一行及其后续行
【发布时间】:2017-09-27 02:31:21
【问题描述】:

给定输入:

1234
5678
9abc
defg
hijk

我想要输出:

12345678
56789abc
9abcdefg
defghijk

有很多示例使用 sed(1) 连接一对线,然后是该对之后的下一对,依此类推。但是我还没有找到将第 1 行与第 2 行、第 2 行与第 3 行、第 3 行与第 4 行连接起来的示例,...

sed(1) 解决方案首选。其他选项不太有趣 - 例如,awk(1)、python(1) 和 perl(1) 实现相当容易。我特别为成功的 sed(1) 咒语难倒。

【问题讨论】:

    标签: sed


    【解决方案1】:

    这样做(现在改进了,感谢potong 的提示):

    $ sed -n 'N;s/\n\(.*\)/\1&/;P;D' infile
    12345678
    56789abc
    9abcdefg
    defghijk
    

    详细说明:

    N                 # Append next line to pattern space
    s/\n\(.*\)/\1&/   # Make 111\n222 into 111222\n222
    P                 # Print up to first newline
    D                 # Delete up to first newline
    

    替换使这两行

    1111
    2222
    

    在模式空间中看起来像1111\n2222

    11112222
    2222
    

    PD 从模式空间打印/删除第一行。

    请注意,直到最后一行,我们才到达脚本底部(D 开始一个新循环),其中N 无法获取新行并且打印如果我们没有使用 -n 抑制它,最后一行是单独的。

    【讨论】:

    • 也许你的答案可以改为sed -n 'N;s/\n\(.*\)/\1&/;P;D' file,但是正如你所指出的,sed '1h;1d;x;G;s/\n//' file 似乎更优雅。
    • 原始版本因 bsd sed 而失败。版本 2 适用于 gnu sed 或 bsd sed。不错。
    • @Juan 那是因为 BSD sed 很难在替换中插入换行符;在& 中嵌入换行符可以解决这个问题。
    • 确实如此。只是指出来。感谢更新版本。
    【解决方案2】:

    sed '1h;1d;x;G;s/\n//'

    我想它可以通过其他方式完成,但这对我有用:

    $ cat in
    1234
    5678
    9abc
    defg
    hijk
    $ sed '1h;1d;x;G;s/\n//' in
    12345678
    56789abc
    9abcdefg
    defghijk
    

    它是如何工作的:我们把第一行用来存放空间,这就是第一行。第一行之后的每一行 - 将其与保留空间交换,将新的保留空间附加到旧的保留空间,删除换行符。

    【讨论】:

    • 不错!在任何情况下都比我的优雅;)
    • 使用 bsd sed 失败:sed: 1: "1{h;d};x;G;s/\n//": extra characters at the end of d command
    • 我想知道是否有办法用 bsd sed 做到这一点。这个版本对于 gnu sed 的效率比@Benjamin W. 的版本(在一个有一百万行的文件上测试)要高效得多。
    • 从手册页中,'终止的“}”必须以换行符开头'。使用 -e 构建 sed 脚本应该可以做到:sed -e '1{h;d' -e '}' -e 'x;G;s/\n//'.
    • 太好了。现在对于只有一行的输入文件的简并情况如何?
    【解决方案3】:

    调整另一个答案(完全归功于@aragaer)以处理单行输入(并且比原始版本更便于 bsd sed 和 gnu sed - 更新:该答案已被编辑便携性的另一种方式):

    % cat >> inputfile << eof
    12
    34
    56
    eof
    
    % sed -e '1{$p;h;d' -e '}' -e 'x;G;s/\n//' inputfile  # bsd + gnu sed [1]
    1234
    3456
    

    % cat joinsuccessive.sed
    1{
     $p;h;d
    }
    x;G;s/\n//
    % sed -f joinsuccessive.sed inputfile
    1234
    3456
    

    这是一个带注释的版本。

    1{                # special case for first line only:
     $p               #  even MORE special case: print current line for input with
                      #  only a single line
     h                # add line 1 to hold space (for joining with successive lines)
     d                # delete pattern space and move to next line (without printing)
    }
    x                 # for lines 2+, swap pattern space (current line) and hold space
    G                 # add newline + hold space (now has current line) to pattern space
                      # (previous line) giving prev line, newline, curr line in pattern
                      # space (and curr line is in hold space)
    s/\n//            # remove newline added by G (between lines) before printing the
                      # pattern space
    

    [1] bsd sed(1) 想要一个右大括号单独在一行上。使用 -e “构建”脚本或将命令放入 sed 脚本文件(并使用 -f joinsuccessive.sed)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 2012-11-19
      • 2012-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多