Sed substitution possible with arithmetic involved?

前端 未结 4 1668
眼角桃花
眼角桃花 2020-12-16 21:18

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<

相关标签:
4条回答
  • 2020-12-16 22:03

    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.

    0 讨论(0)
  • 2020-12-16 22:07

    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.

    0 讨论(0)
  • 2020-12-16 22:08

    (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.

    0 讨论(0)
  • 2020-12-16 22:18

    I always try to solve every problem tagged with sed 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
    
    0 讨论(0)
提交回复
热议问题