9

File I need to modify contains the following:

block: 16, size: 16, start: 8, length: 4

I'd like the file so that values for block, size will be divided by 2 while values for start, length will be multiplied by 2.

Since I have to make such modifications for a whole bunch of files, I am considering using Sed to do the substitution work for me. But I'm not sure calculations are allowed in the matching and substituting process.

4 Answers 4

9

I always try to solve every problem tagged with using sed. But here it would be so easy to accomplish what you are trying to do with awk. (And the use of sed in this case is too difficult.) So, here is my solution using awk:

$ echo "block: 16, size: 16, start: 8, length: 4" | awk '{
    printf "%s %d, %s %d, %s %d, %s %d\n", $1, $2/2, $3, $4/2, $5, $6*2, $7, $8*2
}'
block: 8, size: 8, start: 16, length: 8
1
  • 1
    This doesn't work as expected when the order of entries is different, e. g. "block: 16, start: 8, size: 8, length: 4" Commented Feb 22, 2016 at 15:21
8

(The right tool to do this is awk, but for the fun of a sed exercise...)

It is possible in sed. After all, a multiplication by 2 is set of substitution of the last digit according to some simple rules:

  • 0 --> 0
  • 1 --> 2
  • 2 --> 4
  • 3 --> 6
  • ...
  • 8 --> 16
  • 9 --> 18

To take care of the carry digit, each rules should be written twice.

This sed script, that can be run with sed -f script, do the multiplication by 2 of all the numbers on the input lines:

s/$/\n\n/
:loop
s/0\n1\n/\n\n1/;t loop
s/0\n\n/\n\n0/;t loop
s/1\n1\n/\n\n3/;t loop
s/1\n\n/\n\n2/;t loop
s/2\n1\n/\n\n5/;t loop
s/2\n\n/\n\n4/;t loop
s/3\n1\n/\n\n7/;t loop
s/3\n\n/\n\n6/;t loop
s/4\n1\n/\n\n9/;t loop
s/4\n\n/\n\n8/;t loop
s/5\n1\n/\n1\n1/;t loop
s/5\n\n/\n1\n0/;t loop
s/6\n1\n/\n1\n3/;t loop
s/6\n\n/\n1\n2/;t loop
s/7\n1\n/\n1\n5/;t loop
s/7\n\n/\n1\n4/;t loop
s/8\n1\n/\n1\n7/;t loop
s/8\n\n/\n1\n6/;t loop
s/9\n1\n/\n1\n9/;t loop
s/9\n\n/\n1\n8/;t loop
s/\n1\n/\n\n1/;t loop
s/\(.\)\n\n/\n\n\1/;t loop
s/^\n\n//

Dividing an even number by 2, is the same logic, but from left to right instead of right to left:

s/^/\n\n/
:loop
s/\n1\n0/5\n\n/;t loop
s/\n\n0/0\n\n/;t loop
s/\n1\n1/5\n1\n/;t loop
s/\n\n1/\n1\n/;t loop
s/\n1\n2/6\n\n/;t loop
s/\n\n2/1\n\n/;t loop
s/\n1\n3/6\n1\n/;t loop
s/\n\n3/2\n1\n/;t loop
s/\n1\n4/7\n\n/;t loop
s/\n\n4/2\n\n/;t loop
s/\n1\n5/7\n1\n/;t loop
s/\n\n5/2\n1\n/;t loop
s/\n1\n6/8\n\n/;t loop
s/\n\n6/3\n\n/;t loop
s/\n1\n7/8\n\n/;t loop
s/\n\n7/3\n1\n/;t loop
s/\n1\n8/9\n\n/;t loop
s/\n\n8/4\n\n/;t loop
s/\n1\n9/9\n1\n/;t loop
s/\n\n9/4\n1\n/;t loop
s/\n1\n/5\n\n/;t loop
s/\n\n\(.\)/\1\n\n/;t loop
s/\n\n$//

Combining those, this script do the job:

h
s/, start.*//
s/^/\n\n/
t loopa
:loopa
s/\n1\n0/5\n\n/;t loopa
s/\n\n0/0\n\n/;t loopa
s/\n1\n1/5\n1\n/;t loopa
s/\n\n1/\n1\n/;t loopa
s/\n1\n2/6\n\n/;t loopa
s/\n\n2/1\n\n/;t loopa
s/\n1\n3/6\n1\n/;t loopa
s/\n\n3/2\n1\n/;t loopa
s/\n1\n4/7\n\n/;t loopa
s/\n\n4/2\n\n/;t loopa
s/\n1\n5/7\n1\n/;t loopa
s/\n\n5/2\n1\n/;t loopa
s/\n1\n6/8\n\n/;t loopa
s/\n\n6/3\n\n/;t loopa
s/\n1\n7/8\n\n/;t loopa
s/\n\n7/3\n1\n/;t loopa
s/\n1\n8/9\n\n/;t loopa
s/\n\n8/4\n\n/;t loopa
s/\n1\n9/9\n1\n/;t loopa
s/\n\n9/4\n1\n/;t loopa
s/\n1\n/5\n\n/;t loopa
s/\n\n\(.\)/\1\n\n/;t loopa
s/\n\n$//
H
g
s/.*, start/, start/
s/\n.*//
s/$/\n\n/
t loopb
:loopb
s/0\n1\n/\n\n1/;t loopb
s/0\n\n/\n\n0/;t loopb
s/1\n1\n/\n\n3/;t loopb
s/1\n\n/\n\n2/;t loopb
s/2\n1\n/\n\n5/;t loopb
s/2\n\n/\n\n4/;t loopb
s/3\n1\n/\n\n7/;t loopb
s/3\n\n/\n\n6/;t loopb
s/4\n1\n/\n\n9/;t loopb
s/4\n\n/\n\n8/;t loopb
s/5\n1\n/\n1\n1/;t loopb
s/5\n\n/\n1\n0/;t loopb
s/6\n1\n/\n1\n3/;t loopb
s/6\n\n/\n1\n2/;t loopb
s/7\n1\n/\n1\n5/;t loopb
s/7\n\n/\n1\n4/;t loopb
s/8\n1\n/\n1\n7/;t loopb
s/8\n\n/\n1\n6/;t loopb
s/9\n1\n/\n1\n9/;t loopb
s/9\n\n/\n1\n8/;t loopb
s/\n1\n/\n\n1/;t loopb
s/\(.\)\n\n/\n\n\1/;t loopb
s/^\n\n//
H
g
s/[^\n]*\n//
s/\n//

(Much easier in awk thought.)

Note: I once saw a Turing Machine implementation is sed, so I try to remember that anything that can be done with a programming language can be done in sed. That of course does not mean that sed is the good tool in all situations.

4
  • I haven't tried to understand this but based on your comment it seems this will fail for anything but one digit numbers. You can't replace only the last number in isolation. Commented Aug 5, 2011 at 17:16
  • I know that I can't replace only the last number in isolation. This is why I have 2 \n. For the multiplication, right of it is the solution, and in the middle the carry digit.
    – jfg956
    Commented Aug 5, 2011 at 17:27
  • I’ve been having trouble implementing a similar arithmetic loop in sed (for the challenge, not for a practical purpose). The first t instruction always seems to succeed. t is defined as branching “if any substitutions have been made since the most recent reading of an input line or execution of a t.”, which is true after the initial s/$/\n\n/ instruction. So, if the last digit isn’t 0, no multiplication happens.
    – tjcaul
    Commented Feb 25, 2022 at 7:08
  • Turing machine in sed ? Wow!
    – KSK
    Commented Jun 26, 2023 at 7:18
7

Perl is useful here:

perl -pe '
  s{(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)(\D+)(\d+)}
   {$1 . $2/2 . $3 . $4/2 . $5 . $6*2 . $7 . $8*2}e
' file

If you want to edit your files in-place, perl has a -i option like sed.

1
  • 2
    You mean that sed has the -i option like perl, not the other way around. You will not find a -i option in the required list of options in the POSIX spec for sed, BTW, but rather only occasionally and unofficially in certain vendor ports. READ: sed -i is not universally supported, although perl -i is.
    – tchrist
    Commented Aug 6, 2011 at 11:38
0

Don't think it's possible. See e.g. http://www.delorie.com/gnu/docs/sed/sed_15.html.

However if you only have a small set of possible values for block, size, start, and length, it might be quickest to hard-code the needed substitutions. The next-easiest option is probably to use awk, but that can't modify files in-place.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.