例如,我有一个字符串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)
如何忽略除第一个连字符之外的所有连字符?
您可以使用
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)
第一个解决方案:这样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)