Is there any way to tell sed
to output only captured groups? For example given the input:
This is a sample 123 text and some 987 numbers
and pattern:
/([\d]+)/
Could I get only 123 and 987 output in the way formatted by back references?
The key to getting this to work is to tell sed
to exclude what you don't want to be output as well as specifying what you do want.
string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'
This says:
-n
)p
)In general, in sed
you capture groups using parentheses and output what you capture using a back reference:
echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'
will output "bar". If you use -r
(-E
for OS X) for extended regex, you don't need to escape the parentheses:
echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'
There can be up to 9 capture groups and their back references. The back references are numbered in the order the groups appear, but they can be used in any order and can be repeated:
echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'
outputs "a bar a".
If you have GNU grep
(it may also work in BSD, including OS X):
echo "$string" | grep -Po '\d+'
or variations such as:
echo "$string" | grep -Po '(?<=\D )(\d+)'
The -P
option enables Perl Compatible Regular Expressions. See man 3 pcrepattern
or man
3 pcresyntax
.