Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 第n个字符串匹配,然后删除以下字符串,并使用sed替换新字符串_String_Sed - Fatal编程技术网

String 第n个字符串匹配,然后删除以下字符串,并使用sed替换新字符串

String 第n个字符串匹配,然后删除以下字符串,并使用sed替换新字符串,string,sed,String,Sed,我有这个档案: "Max": 10, "Enable": true, "Min": 2, "Enable": true, "Retries": 5, 我想通过删除Enable:之后的all来更改第二次出现的Enable值,并放入我需要的值。 我不在乎现在在Enable中的哪个值只是为了替换,即使我替换为相同的字符串 我使用了这个命令: sed -re 's/("Enable":)[^:]/\1 false,/2' file > newfile 但我得到的结果是:

我有这个档案:

  "Max": 10,
  "Enable": true,
  "Min": 2,
  "Enable": true,
  "Retries": 5,
我想通过删除Enable:之后的all来更改第二次出现的Enable值,并放入我需要的值。 我不在乎现在在Enable中的哪个值只是为了替换,即使我替换为相同的字符串

我使用了这个命令:

sed -re 's/("Enable":)[^:]/\1 false,/2' file > newfile
但我得到的结果是:

  "Max": 10,
  "Enable": true,
  "Min": 2,
  "Enable": false,true,
  "Retries": 5,
如果可能的话,我需要使用sed命令


谢谢大家!

我知道你说过你想要sed,但是sed是一行上的简单替换,这不是,所以你应该使用awk:

$ awk '/Enable/ && (++c==2) {$2="false,"} 1' file
"Max": 10,
"Enable": true,
"Min": 2,
"Enable": false,
"Retries": 5,

这在sed中比在awk中更为迂回,但还行。您的想法不错,但您遇到了一个问题,即sed以基于行的方式工作:sed将一行读入模式空间,在其上运行代码,然后读取下一行。除非进行特殊处理,否则代码一次只能看到一行,因此它看不到Enable:的第二次出现是第二次出现

解决这个问题的简单方法是,如果文件足够小,可以完全保存在RAM中,则在处理文件之前,先将文件完全读取到RAM中:

sed ':a $! { N; ba }; s/\("Enable":\)[^\n]*/\1 false,/2' filename
即:

:a                                  # jump label for looping
$! {                                # Unless the end of input was reached
  N                                 # fetch the next line, append it
  ba                                # go to :a
}                                   # this reads the whole file into the
                                    # pattern space. Then:
s/\("Enable":\)[^\n]*/\1 false,/2   # replace second occurrence of a matching
                                    # value.
如果您使用的是Mac OS X或BSD:这些都带有BSD sed,这需要一些…啊…说服才能使用跳转指令。我认为应该接受

sed -e ':a' -e '$! { N; ba' -e '}; s/\("Enable":\)[^\n]*/\1 false,/2' filename
或者

sed '1h; 1!H; $!d; x; s/\("Enable":\)[^\n]*/\1 false,/2' filename
除了在保持缓冲区(而不是模式空间)中组装文件外,执行的操作几乎相同

如果文件非常大,可以使用

sed '1 { x; s/^/../; x; }; /"Enable":/ { x; /^.$/ { x; s/:.*/: false,/; x; }; s/.//; x; }' filename
这项工作如下:

1 {                  # in the first line
   x                 # set a counter in the hold buffer
   s/^/../           # two dots here to replace the second occurrence.
   x                 # (use n dots to replace the nth)
}
/"Enable":/ {        # in a matching line:
  x                  
  /^.$/ {            # check the counter. If it is one,
    x
    s/:.*/: false,/  # replace value
    x
  }
  s/.//              # decrease counter
  x
}
x交换保持缓冲区和模式空间,以便保持缓冲区的内容在模式空间中,并且可以使用。他们中的很多人都注意到正确的东西在正确的时间出现在模式空间中。

更新 这个答案中给出的解决方案是将完整的文档读入内存

对于Perl:在两次启用后,将。*替换为false:

在gnuSed中,在使用由NULL char分隔的-z寄存器时,文件将变为 单个寄存器。在这种情况下,可以使用类似于OP暂定的解决方案:

sed -zr 's!"Enable":[^\n]*!"Enable": false!2'
or
sed -zr 's!("Enable":)[^\n]*!\1 false!2'
在sed中使用Perl策略是无效的,因为我们没有像。*?这样的非贪婪regexp运算符?。那么


是错误的:如果我们有两次Enable

加上1,那么它就可以工作,因为语句更为迂回:-。@EdMorton计数器代码实际上在复杂性方面并没有那么糟糕。您必须说服自己将x指令作为一种特殊的大括号来阅读,其中一对大括号表示您正在处理另一个缓冲区的块。这通常是阅读更复杂sed代码的诀窍:您几乎总是看到形式为x的东西;雅达;雅达;十,。如果你不这样做,那就是从“收入”开始的,欣赏小费,但说实话,我只是不想学习如何使用sed做这样的事情,因为awk总是可用的,IMHO几乎总是在每个重要的方面和最不重要的方面都能得到更好的解决方案!。我真的不明白为什么有人用sed来做更多的事情,从本质上说,s/old/new,而不仅仅是为了精神锻炼。在awk中有几个盲点,sed更直接。我知道,更多的情况下,sed是以另一种方式运行的,比如s///2,或者除了gawk的gensub或y//,没有反向引用,编写便携式awk甚至比编写便携式sed更痛苦,因为至少有一种常见的awk-a版本的mawk没有完全遵循POSIX。请注意,有些人提出了两者都被Perl取代的想法,所以我们最好同时关闭它们,嗯PGood解决方案和讨论+1可能会使用更严格的正则表达式,但类似这样的方法是明智的。同意正则表达式,但我不想在这方面投入太多精力,因为OP已经声明他们想要一个sed解决方案。简单明了+1@EdMorton,好的,谢谢,我知道了!我的意思是我在回答中提出的解决方案——我将改变我模棱两可的句子。我不太喜欢空字节分割;问题中的数据看起来有点模糊,字符串中的空字节是允许的,如果很少的话。在Perl的情况下,可以用-0777而不是-0轻松地解决这个问题;对于sed案例,我们将以与我提出的东西非常相似的东西结束。除此之外,Perl解决方案的一个缺点是,适应问题标题中提出的第n个问题(尽管不是问题文本中提出的问题)会更加繁琐。由于Perl中存在计数器变量,我看不出有任何理由在//'中含糊其词并完成整个过程。类似EdMorton的awk解决方案应该可以简单地移植到Perl中,我认为这是更好的算法。请注意,如果输入数据真的是JSON,那么sed和awk都不应该使用,而Perl应该使用JSON库,尽管这可能有些过分;首先,在这种情况下,我会尝试与jq合作。
sed -zr 's!"Enable":[^\n]*!"Enable": false!2'
or
sed -zr 's!("Enable":)[^\n]*!\1 false!2'
sed -zr 's!("Enable"(.|\n)*?"Enable":)[^\n]*!\1 false!' ### WRONG