Does bash support back references in parameter expansion?
ksh93
and zsh
have back-reference (or more accurately1, references to capture groups in the replacement) support inside ${var/pattern/replacement}
, not bash
.
ksh93
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ printf '%s\n' "${var/*@(->*([[:space:]])+([^[:space:]]))*/\1}"
-> r1-ae0-2
zsh
:
$ var='Blah: -> r1-ae0-2 / [123]'
$ set -o extendedglob
$ printf '%s\n' "${var/(#b)*(->[[:space:]]#[^[:space:]]##)*/$match[1]}"
-> r1-ae0-2
(mksh
man page also mentions that future versions will support it with ${KSH_MATCH[1]}
for the first capture group. Not available yet as of 2017-04-25).
However, with bash
, you can do:
$ [[ $var =~ -\>[[:space:]]*[^[:space:]]+ ]] &&
printf '%s\n' "${BASH_REMATCH[0]}"
-> r1-ae0-2
Which is better as it checks that the pattern is found first.
If your system's regexps support \s
/\S
, you can also do:
re='->\s*\S+'
[[ $var =~ $re ]]
With zsh
, you can get the full power of PCREs with:
$ set -o rematchpcre
$ [[ $var =~ '->\s*\S+' ]] && printf '%s\n' $MATCH
-> r1-ae0-2
With zsh -o extendedglob
, see also:
$ printf '%s\n' ${(SM)var##-\>[[:space:]]#[^[:space:]]##}
-> r1-ae0-2
Portably:
$ expr " $var" : '.*\(->[[:space:]]*[^[:space:]]\{1,\}\)'
-> r1-ae0-2
If there are several occurrences of the pattern in the string, the behaviour will vary with all those solutions. However none of them will give you a newline separated list of all matches like in your GNU-grep
-based solution.
To do that, you'd need to do the looping by hand. For instance, with bash
:
re='(->\s*\S+)(.*)'
while [[ $var =~ $re ]]; do
printf '%s\n' "${BASH_REMATCH[1]}"
var=${BASH_REMATCH[2]}
done
With zsh
, you could resort to this kind of trick to store all the matches in an array:
set -o extendedglob
matches=() n=0
: ${var//(#m)->[[:space:]]#[^[:space:]]##/${matches[++n]::=$MATCH}}
printf '%s\n' $matches
1 back-references does more commonly designate a pattern that references what was matched by an earlier group. For instance, the \(.\)\1
basic regular expression matches a single character followed by that same character (it matches on aa
, not on ab
). That \1
is a back-reference to that \(.\)
capture group in the same pattern.
ksh93
does support back-references in its patterns (for instance ls -d -- @(?)\1
will list the file names that consist of two identical characters), not other shells. Standard BREs and PCREs support back-references but not standard ERE, though some ERE implementations support it as an extension. bash
's [[ foo =~ re ]]
uses EREs.
[[ aa =~ (.)\1 ]]
will not match, but
re='(.)\1'; [[ aa =~ $re ]]
may if the system's EREs support it.
You want to delete everything up to the first ␣->␣
(not including the "arrow") and after the last ␣/
(including the space and slash).
string="Blah: -> r1-ae0-2 / [123]"
string=${string/*->/->}
string=${string/ \/*}
$string
will now be -> r1-ae0-2
.
The same two substitutions would turn -> s7-Gi0-0-1:1-US / Foo
into -> s7-Gi0-0-1:1-US
.
Answering this definitively is impossible without knowing the exact format every message takes. However, as a general approach you can print certain specific fields using cut
:
$ cut -d ' ' -f 2 <<< '-> s7-Gi0-0-1:1-US / Foo'
s7-Gi0-0-1:1-US
Or you can print every nth column using awk
:
$ awk -F' ' '{ for (i=2;i<=NF;i+=4) print $i }' <<< '-> r1-ae0-2 / [123], -> s7-Gi0-0-1:1-US / Foo'
r1-ae0-2
s7-Gi0-0-1:1-US