【问题标题】:Sed replace pattern with line numbersed 用行号替换模式
【发布时间】:2021-03-10 10:45:31
【问题描述】:

我需要用当前行号替换模式###

我设法用 AWK 和 SED 在下一行打印。

sed -n "/###/{p;=;}" file 打印到下一行,没有p;,它将替换整行。

sed -e "s/###/{=;}/g" file 在我的脑海中曾经是有意义的,因为 =; 返回匹配模式的行号,但它会返回文本 {=;}

我错过了什么?我知道这是一个愚蠢的问题。我在 sed 手册中找不到这个问题的答案,不太清楚。

如果可能,请指出我缺少什么,以及如何让它发挥作用。谢谢

【问题讨论】:

标签: sed awk gawk


【解决方案1】:

简单awkoneliner:

awk '{gsub("###",NR,$0);print}'

【讨论】:

  • @Thor 也许我做了不同的假设——那不就是把行号放在行首吗?我阅读 OP 的意思是“###”可能在该行的任何位置,因此是 gsub()。虽然在第二次阅读中,似乎在行首的数字可能是你的想法......
【解决方案2】:

鉴于the limitations of the = command,我认为将工作分成两部分(实际上是三部分)更容易。使用 GNU sed 你可以:

$ sed -n '/###/=' test > lineno

然后类似

$ sed -e '/###/R lineno' test | sed '/###/{:r;N;s/###\([^\n]*\n\)\([^\n]*\)/\2\1/;tr;:c;s/\n\n/\n/;tc}'

恐怕sed 没有简单的方法,因为与= 命令一样,r 和GNU 扩展R 命令不会将文件读入模式空间,而是直接将这些行附加到输出中,因此不能以任何方式修改文件的内容。因此管道到另一个 sed 命令。

如果test的内容是

fooo
bar ### aa
test
zz ### bar

上面会产生

fooo
bar 2 aa
test
zz 4 bar

【讨论】:

    【解决方案3】:

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

    sed = file | sed 'N;:a;s/\(\(.*\)\n.*\)###/\1\2/;ta;s/.*\n//'
    

    使用 cat 的替代方法:

    cat -n file | sed -E ':a;s/^(\s*(\S*)\t.*)###/\1\2/;ta;s/.*\t//'
    

    【讨论】:

    • 你能解释一下sed模式吗?
    【解决方案4】:

    正如 Lev Levitsky 所指出的,这不可能通过一次 sed 调用来实现,因为行号直接发送到标准输出。

    您可以 sed 为您编写一个 sed 脚本,然后分两遍进行替换:

    infile

    a
    b
    c
    d
    e
    ###
    ###
    ###
    a
    b
    ###
    c
    d
    e
    ###
    

    找到包含该模式的行:

    sed -n '/###/=' infile
    

    输出:

    6
    7
    8
    11
    15
    

    将其导入 sed 脚本,编写新的 sed 脚本:

    sed 's:.*:&s/###/&/:'
    

    输出:

    6s/###/6/
    7s/###/7/
    8s/###/8/
    11s/###/11/
    15s/###/15/
    

    执行:

    sed -n '/###/=' infile | sed 's:.*:&s/^/& \&/:' | sed -f - infile
    

    输出:

    a
    b
    c
    d
    e
    6
    7
    8
    a
    b
    11
    c
    d
    e
    15
    

    【讨论】:

      【解决方案5】:

      这样好吗?

      kent$  echo "a
      b
      c
      d
      e"|awk '/d/{$0=$0" "NR}1'
      a
      b
      c
      d 4
      e
      

      如果匹配模式“d”,则在行尾附加行号。

      编辑

      哦,你想替换模式而不是附加行号......看看新的cmd:

      kent$  echo "a
      b
      c
      d
      e"|awk '/d/{gsub(/d/,NR)}1'
      a
      b
      c
      4
      e
      

      该行也可以这样写:awk '1+gsub(/d/,NR)' file

      【讨论】:

      • OP 需要用行号替换模式,这不是正确的答案。
      【解决方案6】:

      单行修改FILE,将LINE替换为对应的行号:

      seq 1 `wc -l FILE | awk '{print $1}'` | xargs -IX sed -i 'X s/LINE/X/' FILE
      

      【讨论】:

      【解决方案7】:

      继续https://stackoverflow.com/a/53519367/29924

      如果您在 osx 上尝试此操作,则 sed 的版本不同,您需要这样做:

      seq 1 `wc -l FILE | awk '{print $1}'` | xargs --verbose -IX sed -i bak "X s/__line__/X/" FILE
      

      https://markhneedham.com/blog/2011/01/14/sed-sed-1-invalid-command-code-r-on-mac-os-x/

      【讨论】:

        猜你喜欢
        • 2018-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多