Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed-ish oneliner to perform arithmetic within substitution

Tags:

bash

sed

awk

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.bazquuxFOO=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.

like image 429
intelfx Avatar asked Aug 06 '20 10:08

intelfx


3 Answers

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)
like image 168
Sundeep Avatar answered Oct 17 '22 12:10

Sundeep


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
like image 5
Ed Morton Avatar answered Oct 17 '22 12:10

Ed Morton


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.

like image 4
Wiktor Stribiżew Avatar answered Oct 17 '22 11:10

Wiktor Stribiżew