我想用2.6.2 参数扩展从字符串中删除前导字符,但惊讶地发现“删除最大前缀模式”不会自动重复该模式。
$ x=aaaaabc
$ printf %s\\n "${x##a}"
aaaabc
如您所见,只有第一个a
已被删除。预期输出为、、或中bc
的任何一个。x=bc
x=abc
x=aabc
x=aaabc
x=aaaabc
a
如果我想从 的开头删除尽可能多的内容,我正在努力弄清楚如何编写该模式$x
。我也没有运气搜索其他线程,因为许多答案都使用 bash,但我正在寻找 POSIX shell 解决方案。
答案1
对于某些模式,您可以通过匹配要保留的变量部分来“反转”模式:
$ for x in "" a aa abc aabc aaabc aaabca aaabcabc bc bcaa
> do
> printf %s\\n "${x#"${x%%[!a]*}"}"
> done
bc
bc
bc
bca
bcabc
bc
bcaa
答案2
我认为你不能以通用的方式做到这一点(IE忽略模式的特定功能),仅使用 POSIX shell 构造,而不使用循环:
until [ "${x#a}" = "$x" ]; do x="${x#a}"; done
答案3
a
作为模式匹配a
,它不可能匹配aaa
。
虽然 POSIXsh
规范基于 Korn shell 的子集,并且 Korn shell 具有(匹配 0 个或多个s*(foo)
的序列)和运算符(匹配 1 个或多个 s 的序列,与 相同),但这些并未由POSIX,因为它们不向后兼容 Bourne shell,并且意味着在许多情况下无法使用它们,例如:foo
+(foo)
foo
foo*(foo)
find . -name '*(x)'
当前需要匹配以以下结尾的文件名(x)
pattern='*(x)'; case $file in ($pattern) ...; esac
或者${file##$pattern}
。相同的。您会注意到,在这些情况下 ksh88 或 pdksh 无法识别这些运算符。
正则表达式支持重复。 POSIX 指定了许多可以匹配正则表达式(expr
, grep
, sed
, awk
...)的实用程序。有些 shell 已经或已经内置了其中一些。expr
内置于(或可以内置于)Almquist shell 中。可以使用,和builtinksh93
构建,并且可以在不分叉的情况下获得它们的输出。某些基于 ash 的 shell 还可以在由内置命令的一次调用组成时获得命令替换的输出,而无需分叉。 shell是 shell 的另一个示例,其中所有这些实用程序都可以在不分叉或执行的情况下调用。expr
grep
sed
busybox
另一方面,printf
您在问题中使用的是不是内置于 ksh88 或大多数 pdksh 衍生品中。除了特殊的内置命令和诸如export
/ getopts
/ read
... 之类的内置命令(只能合理地内置)之外,POSIX 不向您保证命令可能是内置的,也可能不是内置的。
所以:
x=$( expr "x$x" : 'xa*\(.*\)' )
a
例如,可以在外壳内部剥离前导s。但有一些注意事项:
- 如果结果是空字符串或 0 的某些表示形式,则返回失败退出状态
- 它还会删除尾随的换行符。
- 您会注意到
x
我们还需要添加前缀,以防止在$x
碰巧包含expr
运算符时失败(请参阅expr
POSIX规范的应用程序使用部分了解更多详情)。
或者与awk
:
x=$(awk 'BEGIN {sub(/^a*/, "", ARGV[1]); print ARGV[1]}' "$x")
或者sed
:
x=$(printf '%s\n' "$x" | sed '1s/^a*//')
(sed
这里最不合适,因为它基于行工作并且需要通过标准输入或文件提供输入)。