a
as a pattern matches a
, there's no way it can match aaa
.
While the POSIX sh
specification is based on a subset of the Korn shell, and the Korn shell has *(foo)
(matches a sequence of 0 or more foo
s) and +(foo)
operators (matches a sequence of one or more foo
s, same as foo*(foo)
), those were not specified by POSIX as they're not backward compatible with those of the Bourne shell, and means there are a number of contexts where they couldn't be used like in:
find . -name '*(x)'
which is currently required to match on filenames that end in (x)
pattern='*(x)'; case $file in ($pattern) ...; esac
or ${file##$pattern}
. Same. You'll notice that ksh88 or pdksh do not recognise those operators in those cases.
Repetition is supported in regular expressions. POSIX specifies a number of utilities that can match regular expressions (expr
, grep
, sed
, awk
...). Some shells have or have had some of those builtin. expr
was built in (or could be made builtin) the Almquist shell. ksh93
can be built with expr
, grep
and sed
builtin and can get their output without forking. Some ash-based shells can also get the output of command substitutions without forking when it's made of one invocation of a builtin command. The busybox
shell is another example of a shell where all those utilities can be invoked without forking nor executing.
On the other hand, printf
which you use in your question is not builtin in ksh88 nor most pdksh derivatives. Appart from the special builtins and builtins such as export
/getopts
/read
... which can only reasonably be builtin, POSIX does not give you guarantee that a command may or may not be builtin.
So:
x=$( expr "x$x" : 'xa*\(.*\)' )
For instance could strip the leading a
s internally in the shell. With a couple of caveats though:
- that returns with a failure exit status if the result is an empty string or some representations of 0
- that also strips trailing newline characters.
- you'll have noticed the
x
prefix we also need to add to prevent that to fail if $x
happens to contain an expr
operator (see the Application Usage section of POSIX expr
specification for more details on that).
Or with awk
:
x=$(awk 'BEGIN {sub(/^a*/, "", ARGV[1]); print ARGV[1]}' "$x")
Or sed
:
x=$(printf '%s\n' "$x" | sed '1s/^a*//')
(sed
being the least appropriate here as it works line-based and need to be fed its input via stdin or a file).
shopt -s extglob; printf '%s\n' "${x##+(a)}"
-- ref 3.5.8.1 Pattern Matching