Sed 仅限于每个输入行一部分的字符替换

Sed 仅限于每个输入行一部分的字符替换,sed,substitution,string-substitution,Sed,Substitution,String Substitution,有一个文件,例如Inventory.conf,其中包含以下行: Int/domain—home.dir=/etc/int 我需要在=之前替换/和-,但不能在之后替换。 结果应该是: Int_domain_home_dir=/etc/int 我尝试了几个sed命令,但似乎没有一个适合我的需要。使用GNU sed: echo 'Int/domain—home.dir=/etc/int' | sed 'h;s/[^=]*//;x;s/=.*//;s/[/—.]/_/g;G;s/\n//' 输出:

有一个文件,例如Inventory.conf,其中包含以下行:

Int/domain—home.dir=/etc/int
我需要在
=
之前替换
/
-
,但不能在之后替换。 结果应该是:

Int_domain_home_dir=/etc/int
我尝试了几个
sed
命令,但似乎没有一个适合我的需要。

使用GNU sed:

echo 'Int/domain—home.dir=/etc/int' | sed 'h;s/[^=]*//;x;s/=.*//;s/[/—.]/_/g;G;s/\n//'
输出:

Int_domain_home_dir=/etc/int Int\u domain\u home\u dir=/etc/Int 请参阅:
man sed
。我想您也要用GNU-sed替换点。

echo 'Int/domain—home.dir=/etc/int' | sed 'h;s/[^=]*//;x;s/=.*//;s/[/—.]/_/g;G;s/\n//'
输出:

Int_domain_home_dir=/etc/int Int\u domain\u home\u dir=/etc/Int
请参阅:
man sed
。我假设您也要替换圆点。

如果
perl
解决方案没有问题:

$ echo 'Int/domain-home.dir=/etc/int' | perl -pe 's#^[^=]+#$&=~s|[/.-]|_|gr#e'
Int_domain_home_dir=/etc/int
  • ^[^=]+
    字符串匹配从行的开头到但不包括第一次出现的
    =
  • $&=~s |[/.-]| | gr
    对匹配的字符串执行另一个替换
    • 将所有
      /
      -
      字符替换为
    • r
      修饰符将返回修改后的字符串
  • e
    修饰符允许在替换部分使用表达式而不是字符串
  • #
    用作分隔符,以避免在字符类
    [/.-]
    内转义
    /
此外,正如@mklement0所建议的,我们可以使用translate而不是内部替换

$ echo 'Int/domain-home.dir=/etc/int' | perl -pe 's#^[^=]+#$&=~tr|/.-|_|r#e'
Int_domain_home_dir=/etc/int


请注意,我已经更改了示例输入,使用了
-
而不是
-
,如果
perl
解决方案没有问题,则OP似乎希望使用
-

$ echo 'Int/domain-home.dir=/etc/int' | perl -pe 's#^[^=]+#$&=~s|[/.-]|_|gr#e'
Int_domain_home_dir=/etc/int
  • ^[^=]+
    字符串匹配从行的开头到但不包括第一次出现的
    =
  • $&=~s |[/.-]| | gr
    对匹配的字符串执行另一个替换
    • 将所有
      /
      -
      字符替换为
    • r
      修饰符将返回修改后的字符串
  • e
    修饰符允许在替换部分使用表达式而不是字符串
  • #
    用作分隔符,以避免在字符类
    [/.-]
    内转义
    /
此外,正如@mklement0所建议的,我们可以使用translate而不是内部替换

$ echo 'Int/domain-home.dir=/etc/int' | perl -pe 's#^[^=]+#$&=~tr|/.-|_|r#e'
Int_domain_home_dir=/etc/int


请注意,我已经更改了示例输入,
-
被使用,而不是
-
,这似乎是OP根据评论想要的您要求的
sed
解决方案,但是在这种情况下
awk
解决方案更简单,性能更好,因为您可以通过
=
轻松地将行拆分为两个字段,然后有选择地将
gsub()
仅应用于第一个字段,以替换感兴趣的字符:

$ awk -F= '{ gsub("[./-]", "_", $1); print $1 FS $2 }' <<< 'Int/domain-home.dir=/etc/int'
Int_domain_home_dir=/etc/int

perl
也提供了优雅的解决方案:

$ perl -F= -ane '$F[0] =~ tr|-/.|_|; print join("=", @F)' <<<'Int/domain-home.dir=/etc/int'
Int_domain_home_dir=/etc/int

如您所见,
awk
解决方案是目前为止最快的,线路内部循环
sed
解决方案的性能最差,大约是12倍。

您要求的是
sed
解决方案,但是awk解决方案更简单,在这种情况下性能更好,因为您可以通过
=
轻松地将行拆分为两个字段,然后有选择地将
gsub()
仅应用于第一个字段,以替换感兴趣的字符:

$ awk -F= '{ gsub("[./-]", "_", $1); print $1 FS $2 }' <<< 'Int/domain-home.dir=/etc/int'
Int_domain_home_dir=/etc/int

perl
也提供了优雅的解决方案:

$ perl -F= -ane '$F[0] =~ tr|-/.|_|; print join("=", @F)' <<<'Int/domain-home.dir=/etc/int'
Int_domain_home_dir=/etc/int

如您所见,
awk
解决方案是目前为止最快的解决方案,线路内部循环
sed
解决方案的性能预计最差,大约为12倍。

sed与
t
循环(BRE):


使用
t
循环(BRE)进行Sed:


欢迎来到堆栈溢出!请出示你的问题。你应该包括一个你有问题的代码,然后我们可以尝试帮助解决具体的问题。您还应该阅读。欢迎使用堆栈溢出!请出示你的问题。你应该包括一个你有问题的代码,然后我们可以尝试帮助解决具体的问题。例如,您还应该阅读.tnx。然而,它并没有取代“-”。我制作了一个test.txt,只有一行:sed“h;s/[^=]*/;x;s/=.*/;s/[-./]/\ug;g;s/\n//”test.txt这是-(u a)test=确实是。请忽略第一条评论:-)下面是我的评论:例如tnx。但是,它没有替换“-”请看下面:我只做了一行test.txt:cat test.txt这是/a.test=确实是/is.just-结果:sed“h;s/[^=]*/;x;s/=.*/;s/[-./]/\ug;s/\n/”test.txt这是/u a\u test=确实是/is.just-这就是为什么不替换“-”我不明白:-(@HoneyBee,在你的问题中,你使用了
-
,我认为它与
-
tnx不同。但是它没有替换“-”。我只使用了一行test.txt:sed“h;s/[^=]*/;x;s/=.*/;s/[-./]/\ug;g;s/\n/.”test.txt这是-_a_test=确实是/is.just-请忽略第一个注释:-)下面是我的注释:例如tnx。但是它没有替换“-”请看下面:我只用一行做了一个test.txt:cat test.txt这是/a.test=确实是/is.just-结果:sed“h;s/[^=]*/;x;s/=././;s/[-./././-././-/\g;s/\n/.”test.txt this-is_a_test=确实如此。这就是为什么不替换“-”我无法理解:-(@HoneyBee,在你的问题中,你使用了
-
,我认为它被称为emdash…它与高级Perl技术的
-
++不同,但是,老实说,即使有解释,它也可能很难理解+/$&=~tr | \/.-| | r/e'@mklement0,谢谢..添加了
tr
替代答案…我个人发现
perl
在大多数情况下都能很好地工作,它结合了
sed
awk
和更多的优点,再加上它的正则表达式h