在一行中使用sed进行多个替换

4

这可能是一个非常基本的问题,但我无法形成适用于此的sed on liner。

考虑这一行:

foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291

我希望将从“@”到空格之间的所有内容替换为逗号分隔。因此,我的预期输出应该如下:
foo,bar,xyz

我尝试使用 sed -e 's/@.*[^ ]/,/g' 命令将内容替换为空格,但它会替换整行(在编写正则表达式时不是很好)。如果有帮助,将不胜感激。

你到底尝试了什么?哪个表达式对你不起作用? - Wiktor Stribiżew
请在您的帖子中使用代码标签添加您已尝试解决此问题所付出的努力,因为我们都在这里学习。 - RavinderSingh13
更新了问题 - g_p
1
尝试使用 sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g' | sed 's/,$//' 命令。 - Wiktor Stribiżew
谢谢,它已经在工作了,你能否发布它作为答案,并且解释一下会非常有帮助。 - g_p
4个回答

3

@字符之前,您可以找到并捕获除了@以外的任何1个或多个字符,然后匹配@和任何0个或多个非空格字符,后跟0个或多个空格字符,并将所有这些替换为占位符到组1和逗号。然后,您需要删除尾随逗号。

请查看sed演示

s='foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291'
echo "$s" | sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g' | sed 's/,$//'

请注意,您还可以使用sed 's/\([^@][^@]*\)@[^[:space:]]*[[:space:]]*/\1,/g'代替POSIX ERE版本。在BRE POSIX中,您应该转义()以形成捕获组,并且+量词应该被转义,或者用aa*结构替换。 详细信息
  • ([^@]+) - 捕获组1:除@外的1个或多个字符
  • @ - @字符
  • [^[:space:]]* - 除空格外的0个或多个字符
  • [[:space:]]* - 0个或多个空格字符
\1是捕获组#1捕获的文本的占位符。
第二个sed 's/,$//'用于删除字符串末尾的逗号,

2
以下的 awk 可以帮助您解决这个问题。
awk 'BEGIN{OFS=","}{for(i=1;i<=NF;i++){sub(/@.*/,"",$i)}} 1'  Input_file

解决方案2:采用Wiktor Stribizew帖子中的代码并稍作修改,将其转换为单个sed

sed -E 's/([^@]+)@[^[:space:]]*[[:space:]]*/\1,/g;s/,$//'  Input_file

1
不错的双重 awksed 解决方案;-) +1!看起来我回答这个问题有点晚了,哈哈 - Allan

2

即使这样做可能有点复杂,但你也可以采用另一种方法。

$ echo "foo@some_text/48183 bar@another-test/22787 xyz@some_another_text/2291" | (tr ' ' ',' | grep -oP '(?=,|^)[^@]+' | tr -d '\n'; echo "")
foo,bar,xyz

不需要替换字符串的一部分,你可以直接提取相关部分。

说明:

  • tr ' ' ',' 用于将所有空格替换为逗号。
  • grep -oP '(?=,|^)[^@]+' 获取@之前的所有内容。它使用带有lookaround的perl正则表达式(强制约束前一个字符是逗号或字符串的开头,并接受除@之外的所有字符)。
  • tr -d '\n' 用于删除grep插入的EOL。
  • 如果您不需要具有结尾的\n,则可以省略echo ""。然后,您可以简化命令:tr ' ' ',' | grep -oP '(?=,|^)[^@]+' | tr -d '\n'

2
你的正则表达式匹配部分的基本问题是,.*在第一个 @ 后面几乎匹配了源字符串的整个剩余部分(这是非常常见的错误),而 [^ ] 则匹配最后一个非空格字符。
如果你使用 @\S+\s* 作为匹配部分,那么 \S+ 将匹配 "非空格" 部分(例如 some_text/48183),而 \s* 将匹配之后的可选空格。
这个替换结果是 foo,bar,xyz,,所以你需要删除最后一个逗号。

正如你所指出的,解决这个问题需要两个不同的操作,也许 sed 's/@\S*\s/,/g;s/@\S*//' file 就足够了。 - potong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接