1

I'm trying to make a simple bashscript, that given an output from git diff of a sql schema definition file, would be able to create an update script and undo script. So having an input like this:

 create table xxx
 (
-       aaa numeric(18) primary key,
-       bbb numeric(18) not null,
-       ccc numeric(18) not null,
+       aaa INT UNSIGNED AUTO_INCREMENT primary key,
+       AlarmId INT UNSIGNED not null,
+       ccc INT UNSIGNED not null,
        ddd smallint not null,
        eee varchar(2),
        fff varchar(2),
    )

let's assume I want to make an update script. I change all create statements into alter's, then strip all unnecessary rows, and finally replace the '+' marks with change statements (it;s mysql script). I do like so:

sed "s/^\s*create/ALTER/g" < $infile | sed "/^\s\|@/d" | sed "/^-/d" | sed "s/^+\s*\(\`\?\w\+\`\?\)/\tCHANGE \1 \1/g"

So I finally get something like this:

ALTER table xxx
        CHANGE aaa aaa INT UNSIGNED AUTO_INCREMENT primary key,
        CHANGE bbb bbb INT UNSIGNED not null,
        CHANGE ccc ccc INT UNSIGNED not null,
        CHANGE ddd ddd smallint not null,
ALTER table yyy
        CHANGE aaa aaa INT UNSIGNED primary key,
        CHANGE bbb bbb smallint not null,
        CHANGE ccc ccc smallint not null,
        CHANGE ddd ddd INT UNSIGNED not null,
        CHANGE eee eee varchar(1024) not null
ALTER table zzz
(and so on)

One last thing I need to do is to complete each statement with a colon - and I got totally stuck there. Basically, I need to find each ALTER statement (or EOF), and add a colon at end of the line above it (possibly replacing an existing comma). I was able to do it in vim using it's s command:

%s/\(,\)\=\_s\+\(ALTER.*\|\%$\)/;\r\2

But I failed to translate this to sed syntax. It appears, that forcing sed to accept a multiline pattern is a hard job. So - can anyone tell me how to do this? I guess sed is not the only option. It just was my first choice (not the best as it appeared :) ) Maybe there are some out-of-the-box solutions, and I'm just re-inventing the wheel?

murison
  • 3,640
  • 2
  • 23
  • 36

2 Answers2

2

Interesting approach (and fragile, too - imagine a change putting several columns on the same line). Perl can help you with semicolons:

 perl -0777 -pe 's/[,\s]+ALTER/;\nALTER/g;
                 s/$/;/' < input > output
  • -0777 "slurps" the whole file (instead of reading it line by line)
  • -p prints what's been read after processing it
  • [,\s]+ matches whitespace and comma, there must be at least one such character (it prevents insertion of semicolon before the first ALTER).
  • The second substitution adds the final semicolon.
choroba
  • 231,213
  • 25
  • 204
  • 289
  • yup, thought about perl. hard to imagine better tool for text processing. +1 for you. any other ideas? – murison Oct 22 '15 at 08:28
0
sed -n '
   /^[[:blank:]]*create/ {
      s//ALTER/
      H
      b
      }

   /^+\([[:blank:]]*\)\([^[:blank:]]\{1,\}\)/ {
      s//\1CHANGE \2 \2/
      H
      }
   $ !b

   x
   s/,\(\nALTER\)/;\1/g
   s/.\(.*\),$/\1;/p
   ' YourFile

You need to use holding buffer to work with all (several) lines together (action x, H here)

NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43