如何在 sed 中仅获取第一次出现的连字符?

Ala*_*ith 6 regex bash sed

例如,我有一个字符串home/JOHNSMITH-4991-common-task-list,我想取出大写部分和中间有连字符的数字。我回显字符串并将其通过管道传递给 sed 像这样,但我不断收到我不想要的所有连字符,例如:

echo home/JOHNSMITH-4991-common-task-list | sed 's/[^A-Z0-9-]//g'
Run Code Online (Sandbox Code Playgroud)

给我:

JOHNSMITH-4991---
Run Code Online (Sandbox Code Playgroud)

我需要:

JOHNSMITH-4991
Run Code Online (Sandbox Code Playgroud)

如何忽略除第一个连字符之外的所有连字符?

Wik*_*żew 7

您可以使用

sed 's,.*/\([^-]*-[^-]*\).*,\1,' 
Run Code Online (Sandbox Code Playgroud)

POSIX BRE 正则表达式详细信息

  • .*- 任何零个或多个字符
  • /- 一个/字符
  • \([^-]*-[^-]*\)- 第 1 组:除了-、连字符之外的任何零个或多个字符,然后又是除了-
  • .*- 任何零个或多个字符

替换是第 1 组占位符 ,\1以仅恢复捕获的文本。

请参阅在线演示

#!/bin/bash
s="home/JOHNSMITH-4991-common-task-list"
sed 's,.*/\([^-]*-[^-]*\).*,\1,' <<< "$s"
# => JOHNSMITH-4991
Run Code Online (Sandbox Code Playgroud)


Rav*_*h13 5

第一个解决方案:这样awk会更容易,我们可以保持简单,请尝试按照您显示的示例进行编写和测试。

echo "echo home/JOHNSMITH-4991-common-task-list" | awk -F'/|-' '{print $2"-"$3}'
Run Code Online (Sandbox Code Playgroud)

解释:简单的解释是,将字段分隔符设置为/OR-并打印-当前行的第二个字段和第三个字段。



第二种解决方案:使用match的功能awk

echo "echo home/JOHNSMITH-4991-common-task-list" | 
awk '
match($0,/\/[^-]*-[^-]*/){
  print substr($0,RSTART+1,RLENGTH-1)
}'
Run Code Online (Sandbox Code Playgroud)

第三种解决方案:这里使用 GNUgrep解决方案。使用-oP的选项grep,使用 o 选项打印匹配的值,并使用P选项启用 ERE(扩展正则表达式)。然后在主程序中grep使用.*/后跟\K忽略先前的匹配部分,然后提到[^-]*-[^-]*确保-在匹配行中第二次出现之前获取值。

echo "echo home/JOHNSMITH-4991-common-task-list" | grep -oP '.*/\K[^-]*-[^-]*'
Run Code Online (Sandbox Code Playgroud)