我需要一个sed命令,它接受一个字符串并从头开始删除第一个字符的所有副本(但不是从字符串的其余部分删除)。
例如,AAABAC应该生成BAC,因为第一个字母是A,所以我们从头开始删除整个A的运行。
我最初的想法是:
data=$(echo $data | sed 's/^.\+\(.*\)/\1/')
但这不起作用(输出空字符串)。如果我用特定字符替换第一个.
,它将只为该字符成功工作,但我无法正确地将它传到通配符。
我认为.
匹配我想要的第一个字符,但+
不记得我想要的字母,并继续接受每个字符,直到字符串结束,所以括号什么都没有,所以整个字符串都没有被替换。我怎样才能最初接受任何角色,然后“锁定”+
的那个角色?
答案 0 :(得分:7)
您可以使用:
$> s='AAABAC'
$> sed -E 's/^(.)\1*//' <<< "$s"
BAC
(.)
将匹配第一个字符,并在第1组\1*
将匹配0个或更多相同字符的实例或者这是一种纯粹的BASH方式:
$> shopt -s extglob
$> echo "${s##+(${s:0:1})}"
BAC
${s:0:1}
为我们提供了$s
的第一个字符,##+(${s:0:1})
从头开始删除了第一个字符的所有实例。
答案 1 :(得分:3)
针对可移植性提供关于现有答案的路线图:
注意:可以从问题中使用的语法和接受的答案中推断出 GNU sed
正被使用,但问题不在于:如此标记,可能会引起更广泛的兴趣。
anubhava's helpful answer适用于 GNU sed
,但不适用于(更多)严格遵守POSIX的sed
实施,例如在macOS上找到的实现
Benjamin W.'s helpful answer适用于 GNU grep
,因为需要-P
选项支持PCRE,其他grep
实现,例如在macOS上找到的那个,不支持。
soronta's helpful answer适用于使用GNU正则表达式库(大多数Linux发行版)的平台,或者更一般地,适用于其ERE(扩展正则表达式)语法的平台支持反向引用,作为POSIX spec.
的非标准扩展=~
,Bash的正则表达式匹配运算符,是行为依赖于平台的罕见Bash功能之一,因为使用了相应的平台&#39 ; s正则表达式库。这里有一个符合POSIX标准的解决方案,应该适用于所有类似现代Unix的平台,因为它使用 BRE ( basic 正则表达式),POSIX 为其指定反向引用支持:
$ echo 'AAABAC' | sed 's/^\(.\)\1*//'
BAC
答案 2 :(得分:2)
如果你的grep理解Perl兼容的正则表达式,你可以用grep做到这一点:
$ grep -Po '^(.)\1*\K.*' <<< 'AABAC'
BAC
或
$ grep -Po '^(.)\1*\K.*' <<< 'ABAC'
BAC
-o
仅保留匹配项,\K
是一个可变长度的后视,从字符串开头删除尽可能多的相同字符。
答案 3 :(得分:2)
Bash还支持正则表达式:
$ m='(.)(\1+)(.+)'; [[ AAAAABAC =~ $m ]]; printf '%s' "${BASH_REMATCH[3]}"
BAC
适用于GNU ERE正则表达式系统库(因系统而异)。