Sunday, February 17, 2008

Sequence subtration, one liner


The file myfile.out contains a series of digits. The purpose is subtract 1st number from 2nd number(2nd-1st),3rd number minus 2nd number and so on

$ cat myfile.out
10
30
5
802
96

i.e
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac | paste -sd"- " | tr ' ' '\n' | tac | sed -e 's/-/ & /' -e 's/[0-9].* - .[0-9]*/echo `expr &`/'
echo `expr 30 - 10`
echo `expr 5 - 30`
echo `expr 802 - 5`
echo `expr 96 - 802`

The breakdown in each of the pipes:

Adding a duplicate of each digit
$ sed -e 's/[0-9]*/&\n&/' myfile.out
10
10
30
30
5
5
802
802
96
96

Deleting 1st and last line
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d'
10
30
30
5
5
802
802
96

Reversing
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac
96
802
802
5
5
30
30
10

Making the format using "paste" command
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac | paste -sd"- "
96-802 802-5 5-30 30-10

Replacing each space with newline
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac | paste -sd"- " | tr ' ' '\n'
96-802
802-5
5-30
30-10

Again reversing
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac | paste -sd"- " | tr ' ' '\n' | tac
30-10
5-30
802-5
96-802

Formating
$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac | paste -sd"- " | tr ' ' '\n' | tac | sed -e 's/-/ & /' -e 's/[0-9].* - .[0-9]*/echo `expr &`/'
echo `expr 30 - 10`
echo `expr 5 - 30`
echo `expr 802 - 5`
echo `expr 96 - 802`

Now

$ sed -e 's/[0-9]*/&\n&/' myfile.out | sed -e '1d' -e '$d' | tac | paste -sd"- " | tr ' ' '\n' | tac | sed -e 's/-/ & /' -e 's/[0-9].* - .[0-9]*/echo `expr &`/' > myfile1.out

Executing myfile1.out
$ sh myfile1
20
-25
797
-706

ohh! it was a long one liner, good to learn the uses of different sed operations. The same can be achieved in a very traditional way:

FILE=./myfile.out
N=1
total=`sed -n '$=' $FILE`
until [ "$N" -eq $total ]
do
S1=$N
S2=`expr $N + 1`
N=$S2
VAL1=`sed -n "$S1 p" $FILE`
VAL2=`sed -n "$S2 p" $FILE`
expr $VAL2 - $VAL1
done

1 comment:

Horace McGinley said...

that was quite ingenious...very well done...Your explanations are exceptionally clear and very approachable.
I am a neophyte when it comes to shell programming and domain specific languages like paste/AWK/SED/M4. I really appreciate the unique and interesting examples

© Jadu Saikia www.UNIXCL.com