Reputation: 2764
I have a string of form FOO_123_BAR.bazquux
, where FOO
and BAR
are fixed strings, 123
is a number and bazquux
is freeform text.
I need to perform a text transformation on this string: extract 123
and bazquux
, increment the number and then arrange them in a different string.
For example, FOO_123_BAR.bazquux
⇒ FOO=124 BAR=bazquux
.
(Actual transformation is more complex.)
Naturally, I can do this in a sequence of sed and expr calls, but it's ugly:
shopt -s lastpipe
in=FOO_123_BAR.bazquux
echo "$in" | sed -r 's|^FOO_([0-9]+)_BAR\.(.+)$|\1 \2|' | read number text
out="FOO=$((number + 1)) BAR=$text"
Is there a more powerful text processing tool that can do the job in a single invocation? If yes, then how?
Edit: I apologize for not making this clearer, but the exact structure of the input and output is an example. Thus, I prefer general solutions that work with any delimiters or absence thereof, rather than solutions that depend on e. g. presence of underscores.
Upvotes: 5
Views: 153
Reputation: 10133
A pure bash
one-liner would be
[[ $s =~ FOO_([0-9]+)_BAR\.(.*) ]] && echo "FOO=$((BASH_REMATCH[1] + 1)) BAR=${BASH_REMATCH[2]}"
assuming the variable s
is set to the string that is being parsed before calling that line (s=FOO_123_BAR.bazquux
).
Upvotes: 2
Reputation: 204015
Using any awk in any shell on every UNIX box and assuming none of your substrings contain _
or .
:
$ s='FOO_123_BAR.bazquux'
$ echo "$s" | awk -F'[_.]' '{print $1"="$2+1,$3"="$4}'
FOO=124 BAR=bazquux
Upvotes: 5
Reputation: 133640
Could you please try following, written and tested with shown samples in GNU awk
.
1st solution: Adding solution with match
function awk
.
echo "FOO_123_BAR.bazquux" |
awk '
match($0,/FOO_[0-9]+_BAR/){
split(substr($0,RSTART,RLENGTH),array,"_")
print array[1]"="array[2]+1,array[3] "=" substr($0,RSTART+RLENGTH+1)
}'
2nd solution:
echo "FOO_123_BAR.bazquux" |
awk '
BEGIN{
FS="_"
}
{
$2+=1
sub(/_/,"=")
sub(/_/," ")
sub(/\./,"=")
}
1'
Upvotes: 3
Reputation: 7287
Using var substitution:
in=FOO_123_BAR.bazquux
raw=(${in//_/ })
$ echo "$raw=$[raw[1]+1] ${raw[2]//./=}"
FOO=124 BAR=bazquux
Upvotes: 1
Reputation: 23677
With GNU sed
, you can execute the entire replacement string as an external command using the e
flag.
$ s='FOO_123_BAR.bazquux'
$ echo "$s" | sed -E 's/^FOO_([0-9]+)_BAR\.(.+)$/echo FOO=$((\1 + 1)) BAR=\2/e'
FOO=124 BAR=bazquux
To avoid conflict with shell metacharacters, you need to quote the unknown portions:
$ s='FOO_123_BAR.$x(1)'
$ echo "$s" | sed -E 's/^FOO_([0-9]+)_BAR\.(.+)$/echo FOO=$((\1 + 1)) BAR=\2/e'
sh: 1: Syntax error: "(" unexpected
$ echo "$s" | sed -E 's/^FOO_([0-9]+)_BAR\.(.+)$/echo FOO=$((\1 + 1)) BAR=\x27\2\x27/e'
FOO=124 BAR=$x(1)
Upvotes: 6
Reputation: 627103
You may do it with perl
:
perl -pe 's|^FOO_([0-9]+)_BAR\.(.+)$|"FOO=" . ($1 + 1) . " BAR=" . $2|e' <<< "$in"
See the online demo
The ($1 + 1)
will increment the number captured in Group 2.
Upvotes: 4