Owen
Owen

Reputation: 33

How to multiply a number by 2 using sed?

I have a text file named test.sql. How can I use the sed command to multiply the numbers in char and varchar by 2? Thank you.

The original content is:

create table test_table
(
test01 char(40),
test02 date,
test03 varchar(80),
test04 decimal(9,2) not null ,
test05 varchar(100),
test06 serial not null
);

I hope to use the sed command to change the content to the following:

create table test_table
(
test01 char(80),
test02 date,
test03 varchar(160),
test04 decimal(9,2) not null ,
test05 varchar(200),
test06 serial not null
);

I tried the following commands with no success.

sed -E 's:(char|varchar|nvarchar)\(([0-9]+)\):print  \1\(\2 * 2\):g ' test.sql
sed -E "s/(char|varchar)\(([0-9]+)\)/\1\(echo "\\2*2"|bc\)/g" test.sql
[root@owen-test ~]# sed -E 's:(char|varchar|nvarchar)\(([0-9]+)\):print  \1\(\2 * 2\):g ' test.sql
create table test_table
(
test01 print  char(40 * 2),
test02 date,
test03 print  varchar(80 * 2),
test04 decimal(9,2) not null ,
test05 print  varchar(100 * 2),
test06 serial not null
);

[root@owen-test ~]# sed -E "s/(char|varchar)\(([0-9]+)\)/\1\(echo "\\2*2"|bc\)/g" test.sql
create table test_table
(
test01 char(echo 40*2|bc),
test02 date,
test03 varchar(echo 80*2|bc),
test04 decimal(9,2) not null ,
test05 varchar(echo 100*2|bc),
test06 serial not null
);

Upvotes: 3

Views: 121

Answers (4)

potong
potong

Reputation: 58518

This might work for you (GNU sed and shell):

sed 's/char(\([0-9]\+\))/char($((2*\1)))/;s/.*/echo "&"/e' file

Replace the positive integer(s) between brackets with a shell arithmetic expression and then evaluate it.

Upvotes: 1

dimich
dimich

Reputation: 1898

With GNU sed you can do

sed '
    s/\(["`$]\+\)/\\\1/g;
    s/\(char\|varchar\|nvarchar\)(\([0-9]\+\))/\1(\$(expr \2 \\* 2))/;
    s/.*/echo "\0"/e
' test.sql

First command:

s/\(["`$]\+\)/\\\1/g

escapes special shell characters in input.

Second command:

s/\(char\|varchar\|nvarchar\)(\([0-9]\+\))/\1(\$(expr \2 \\* 2))/

replaces number N in parentheses after matched prefix with string $(expr N \* 2).

Third command command:

s/.*/echo "\0"/e

converts entire line S into string echo "S" and executes it as shell command.

If shell supports arithmetic evaluation, for second command you can also use:

s/\(char\|varchar\|nvarchar\)(\([0-9]\+\))/\1(\$((\2\*2)))/

This variant replaces number N with expression $((N*2)).

Note: e modifier in sed is GNU extension.

Note: input data is executed as a part of shell command, therefore this is unsafe solution for arbitrary input.

Upvotes: 2

Toby Speight
Toby Speight

Reputation: 30931

If you can isolate the number in the pattern space, then a small sed program can double any integer:

s/[56789]/,&/g
y/123456789/246802468/

:a
s/9,/,0/g
s/0,/1/g
s/1,/2/g
s/2,/3/g
s/3,/4/g
s/4,/5/g
s/5,/6/g
s/6,/7/g
s/7,/8/g
s/8,/9/g
ta
s/,/1/

Since , may appear in your input, we'll need to use a different symbol for the carry indicator.


To make this work for the input shown, we need to split the line at char(, and save the first half in the hold space (so that we don't double the digits in test๐‘›๐‘›):

#!/usr/bin/sed -f

# Only modify lines containing 'char('
/char(/{

# Save a copy, and remove prefix
h
s/.*char(//

# Double the digit-sequences
s/[56789]/%&/g
y/123456789/246802468/

:a
s/9!/!0/g
s/0!/1/g
s/1!/2/g
s/2!/3/g
s/3!/4/g
s/4!/5/g
s/5!/6/g
s/6!/7/g
s/7!/8/g
s/8!/9/g
ta
s/!/1/

# Retrieve the stored copy; remove its suffix
x
s/char(.*/char(/

# Append the doubled number
G
s/\n//

}

Demo:

$ ./79472059.sed <<<'create table test_table
(
test01 char(40),
test02 date,
test03 varchar(80),
test04 decimal(9,2) not null ,
test05 varchar(100),
test06 serial not null
);'

create table test_table
(
test01 char(80),
test02 date,
test03 varchar(160),
test04 decimal(9,2) not null ,
test05 varchar(200),
test06 serial not null
);

Upvotes: 2

KamilCuk
KamilCuk

Reputation: 141698

It is impossible to multiply a number using sed. Use a different tool.

sed is a string replacement tool. It can replace 80 by 160 and replace 40 by 80. You can then hardcode each possible number and that way implement arithmetic using string replacements. It would result it in a very big boring long hobby project.

Use a different tool. Typically, when sed is not enough or becomes unreadable, use awk. Or use python or perl.

When using GNU sed, then sed can call the shell, and shell can then calculate the value or call another external program to do the calculation. Still this looks way way way easier with GNU awk:

awk '
  match($0, /(.*)(char|varchar|varchar)\(([0-9]+)\)(.*)/, arr) {
    $0 = arr[1] arr[2] "(" (arr[3] * 2) ")" arr[4];
  }
  1
'

Upvotes: 4

Related Questions