如何使用 vi 或 sed 替换指定字符串之间多次出现的字符?
How do I replace multiple occurrence of a character between specified strings using vi or sed?
我正在尝试仅在“,”出现在 65510 和“i”之间时替换它:
2001::/32,fd00::230:5,0,100,0,65510,6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660,i
所以期望的输出是:
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
我试过以下方法:
sed -e 's/,\([^65510]*\)i/_i/' input-file.txt
但是输出只替换了最后一个",":
2001::/32,fd00::230:5,0,100,0,65510,6939_i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660_i
您能否尝试在 GNU awk
.
中使用显示的示例进行跟踪、编写和测试
awk '
match([=10=],/65510.*i/){
val=substr([=10=],RSTART,RLENGTH)
gsub(/,/,"_",val)
print substr([=10=],1,RSTART-1) val substr([=10=],RSTART+RLENGTH)
}
' Input_file
更通用的答案: 如果 i
出现不止一次,它可能会出现也可能不会出现在像 65510....i....i
这样的系列中,然后可以尝试以下。
awk '
{
line=""
while(match([=11=],/65510[^i]*/)){
val=substr([=11=],RSTART,RLENGTH+1)
gsub(/,/,"_",val)
line=(line?line:"")substr([=11=],1,RSTART-1) val
[=11=]=substr([=11=],RSTART+RLENGTH+1)
}
if([=11=]!=""){
line=line [=11=]
}
print line
}
' Input_file
这可能适合您 (GNU sed):
sed -E '/\b65510\b.*i/{:a;s/\b(65510\b[^,i]*),([^i])/_/;ta}' file
如果当前行包含 65510
,然后是 i
,请将它们之间的任何 ,
替换为 _
。
对于 sed
你可以使用一个循环:
[STEP 101] $ cat file
2001::/32,fd00::230:5,0,100,0,65510,6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660,i
[STEP 102] $
[STEP 103] $ sed -e :loop -e 's/\(,65510.*\),\(.*,i\)/_/; tloop' file
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
[STEP 104] $
[STEP 105] $ # if your sed supports -E it can be a bit simpler --
[STEP 106] $ sed -E -e :loop -e 's/(,65510.*),(.*,i)/_/; tloop' file
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
关于t
命令:
t
label
If a s///
has done a successful substitution since the last input line was read and since the last t
or T
command, then branch to label; if label is omitted, branch to end of script.
您可以使用酷炫的 sed 调试工具 sedsed 看看它是如何工作的:
使用 GNU awk 将第 3 个参数匹配 () 和 gensub():
$ awk 'match([=10=],/(.*,)(65510.*)(,i.*)/,a){[=10=]=a[1] gensub(/,/,"_","g",a[2]) a[3]} 1' file
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
上面只是将每个输入行分成 3 部分([=11= 之前的逗号部分),65510
到 [=13= 之前的逗号之前的字符的部分,以及该行的其余部分)然后将中间部分的每个 ,
替换为 _
并将这 3 个部分重新粘贴在一起以形成修改后的输出行。如果输入行不包含 ,65510.*,i
则保持原样。
如果 ,65510x,.*,i
(其中 x
是不是逗号的任何字符)可以存在于您的输入中,它将失败 - 如果可能发生,则将其包含在您问题的示例中。
你可以试试 Perl
$ cat lou.txt
2001::/32,fd00::230:5,0,100,0,65510,6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660,i
$ perl -pe ' s/65510\K(.+?)(?=,i)/$c=;$c=~s!,!_!g;$c/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
或
$ perl -pe ' s/(?=65510)(.+?)(?=,i)/$c=;$c=~s!,!_!g;$c/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
如果你确定65510之前总会有一个逗号,那么
$ perl -pe ' s/,(?=65510)(.+?)(?=,i)/$c=;$c=~s!,!_!g;sprintf(",%s",$c)/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
如果65510两边用逗号包裹,则
$ perl -pe ' s/,(?=65510,)(.+?)(?=,i)/$c=;$c=~s!,!_!g;sprintf(",%s",$c)/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
我正在尝试仅在“,”出现在 65510 和“i”之间时替换它:
2001::/32,fd00::230:5,0,100,0,65510,6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660,i
所以期望的输出是:
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
我试过以下方法:
sed -e 's/,\([^65510]*\)i/_i/' input-file.txt
但是输出只替换了最后一个",":
2001::/32,fd00::230:5,0,100,0,65510,6939_i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660_i
您能否尝试在 GNU awk
.
awk '
match([=10=],/65510.*i/){
val=substr([=10=],RSTART,RLENGTH)
gsub(/,/,"_",val)
print substr([=10=],1,RSTART-1) val substr([=10=],RSTART+RLENGTH)
}
' Input_file
更通用的答案: 如果 i
出现不止一次,它可能会出现也可能不会出现在像 65510....i....i
这样的系列中,然后可以尝试以下。
awk '
{
line=""
while(match([=11=],/65510[^i]*/)){
val=substr([=11=],RSTART,RLENGTH+1)
gsub(/,/,"_",val)
line=(line?line:"")substr([=11=],1,RSTART-1) val
[=11=]=substr([=11=],RSTART+RLENGTH+1)
}
if([=11=]!=""){
line=line [=11=]
}
print line
}
' Input_file
这可能适合您 (GNU sed):
sed -E '/\b65510\b.*i/{:a;s/\b(65510\b[^,i]*),([^i])/_/;ta}' file
如果当前行包含 65510
,然后是 i
,请将它们之间的任何 ,
替换为 _
。
对于 sed
你可以使用一个循环:
[STEP 101] $ cat file
2001::/32,fd00::230:5,0,100,0,65510,6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660,i
[STEP 102] $
[STEP 103] $ sed -e :loop -e 's/\(,65510.*\),\(.*,i\)/_/; tloop' file
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
[STEP 104] $
[STEP 105] $ # if your sed supports -E it can be a bit simpler --
[STEP 106] $ sed -E -e :loop -e 's/(,65510.*),(.*,i)/_/; tloop' file
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
关于t
命令:
t
label
If a
s///
has done a successful substitution since the last input line was read and since the lastt
orT
command, then branch to label; if label is omitted, branch to end of script.
您可以使用酷炫的 sed 调试工具 sedsed 看看它是如何工作的:
使用 GNU awk 将第 3 个参数匹配 () 和 gensub():
$ awk 'match([=10=],/(.*,)(65510.*)(,i.*)/,a){[=10=]=a[1] gensub(/,/,"_","g",a[2]) a[3]} 1' file
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
上面只是将每个输入行分成 3 部分([=11= 之前的逗号部分),65510
到 [=13= 之前的逗号之前的字符的部分,以及该行的其余部分)然后将中间部分的每个 ,
替换为 _
并将这 3 个部分重新粘贴在一起以形成修改后的输出行。如果输入行不包含 ,65510.*,i
则保持原样。
如果 ,65510x,.*,i
(其中 x
是不是逗号的任何字符)可以存在于您的输入中,它将失败 - 如果可能发生,则将其包含在您问题的示例中。
你可以试试 Perl
$ cat lou.txt
2001::/32,fd00::230:5,0,100,0,65510,6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510,6939,2516,7660,7660,7660,i
$ perl -pe ' s/65510\K(.+?)(?=,i)/$c=;$c=~s!,!_!g;$c/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
或
$ perl -pe ' s/(?=65510)(.+?)(?=,i)/$c=;$c=~s!,!_!g;$c/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
如果你确定65510之前总会有一个逗号,那么
$ perl -pe ' s/,(?=65510)(.+?)(?=,i)/$c=;$c=~s!,!_!g;sprintf(",%s",$c)/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$
如果65510两边用逗号包裹,则
$ perl -pe ' s/,(?=65510,)(.+?)(?=,i)/$c=;$c=~s!,!_!g;sprintf(",%s",$c)/ge ' lou.txt
2001::/32,fd00::230:5,0,100,0,65510_6939,i
2001:200:900::/40,fd00::230:5,0,100,0,65510_6939_2516_7660_7660_7660,i
$