sed and awk to insert a line after a para

hi

I am having a file like this

##############################

mod1 ( a(ll) , b(
c), try(o) , oll(ll)
go(oo) , al(ll)
mm(al) , lpo(kka)
kka(oop) );

mod2 ( jj(ll) , c(
kk), try1q(o1) , ofll(lll)
gao(oo1) , ala(llaa)
mmf(adl) , lddpo(kkad)
kkda(oodp) );

##########################################

I want to match the regular expression line mod1 and mod2 in the file and insert a line

#####################
ak(kk) , akjj(ll) , aa(99k) 

after the module ending before ));

Output file

mod1 ( a(ll) , b(
c), try(o) , oll(ll)
go(oo) , al(ll)
mm(al) , lpo(kka)
kka(oop) ,ak(kk) , akjj(ll) , aa(99k) );

mod2 ( jj(ll) , c(
kk), try1q(o1) , ofll(lll)
gao(oo1) , ala(llaa)
mmf(adl) , lddpo(kkad)
kkda(oodp) ,ak(kk) , akjj(ll) , aa(99k) );

##############################

I am using below command

sed '/mod1/a ak(kk) , akjj(ll) , aa(99k)' file1 
sed '/mod2/a ak(kk) , akjj(ll) , aa(99k)' file1 

but it is appending text after match only

Please let me know how it can work

sed 's/;/ak(kk) , akjj(ll) , aa(99k);/g'

Thanks Protocomm

But this is a small section of the file
so I need to match with mod1 and mod2 regular expression and insert the line where those modules are ending before ));

Thanks
Kshitij

Try:

awk '
$1 ~ /^mod[12]$/ {
	add = 1
}
add && /[)];/ {
	sub(/[)];/, ",ak(kk) , akjj(ll) , aa(99k) );")
	add = 0
}
1' file

If you want to use this on a Solaris/SunOS system, use /usr/xpg4/bin/awk or /usr/xpg6/bin/awk instead of just awk .

Maybe you can prepend the stuff?

sed '
/mod1 (/ s//& ak(kk) , akjj(ll) , aa(99k) ,/
/mod2 (/ s//& ak(kk) , akjj(ll) , aa(99k) ,/
' file1

Don Cragun,
I don't understand the working of the variable add ???
Could you explain please ?
if add is equal to 1 then you do sub ?
but why 1 && /[)];/ allow it ?

Thanx

Probably you understand, if it becomes more explicit

( add==1 && /[)];/ ) { ... }

or

{ if ( add==1 && /[)];/ ) { ... }
}

NB && means AND

1 Like

If i understand, the AND && is an logical and then 1 && 1=1 (1 && 0=0)

1 Like

Here is a version of the script with comments:

awk '
$1 ~ /^mod[12]$/ {
	# If the 1st field on a line is "mod1" or "mod2", note that we need to
	# add text to the next line containing ");".
	add = 1
}
add && /[)];/ {
	# If add is not zero and is not the empty string, and the current line
	# contains ");", add in the desired text and clear add.
	sub(/[)];/, ",ak(kk) , akjj(ll) , aa(99k) );")
	add = 0
}
1	# Print the (possibly modified) input line.  ("{print $0}" is the
	# default action when no explicit action is specified.)
' file
2 Likes

Thank you all !
Its working ! but is it possible to provide equivalent sed command
since I need to write to the same file with -i option of sed
I dont think with awk we can write to the same file

Redirect the output of awk to a temp file and then copy the temp file to the original file.

Using:

sed -i.backup 'sed_commands' filename

is (as chacko193 said) roughly equivalent to:

cp filename filename.backup && \
awk 'awk_commands' filename.backup > filename

if you can rewrite the simple awk script we provided into a script using sed commands to get the same results.

On the other hand:

sed -i 'sed_commands' filename

is a disaster waiting to happen. (An I/O error, lack of disk space, power failure, etc. will result in loss of data.)

an other solution:

var=$(command awk < file);echo "$var" > file

Try that on a 100GB file...

1 Like

This is extremely dangerous.

First, I assume you mean awk command in the generic sense, rather than command awk literally (which does something entirely different).

If the awk script fails for any reason, the contents of file will be destroyed. Depending on the operating system and shell you're using, echo "$var" may modify the contents of file if the expansion of $var contains any backslash ( \ ) characters or starts with a minus-sign ( - ) character.

1 Like

thanks for your explications, i'm not an expert as you, i use always the same OS (OSX) and the same shell (bash 3.2), in my case i think that $var don't modify the contents of file

message to MadeInGermany
I never work with bigger file text.

Thx

Hi protocomm,
Try the following script:

var=$(awk '1' < file);echo "$var" > file

on OS X using bash when file contains:

-n

I think you will find that it changes the contents from the three characters - , n , and <newline> to an empty file.

On some other operating systems, much more common file contents could be converted in ways (some obvious and some subtle) that would render working shell scripts or correct C source code contained in file into streams of syntax errors.

I try your line code and after the treatment and put

-n

in the file, the contents not change, the file is the same that before

Interesting...

bash-3.2$ bash --version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.
bash-3.2$ printf -- "-n\n" > file
bash-3.2$ ls -l file
-rw-r--r--  1 dwc  staff  3 May 13 09:45 file
bash-3.2$ var=$(awk '1' < file);echo "$var" > file
bash-3.2$ ls -l file
-rw-r--r--  1 dwc  staff  0 May 13 09:46 file
bash-3.2$ 

i have the same result that you demonstrate�
But if i put something after the -n\n , the file is not empty�

In fact i don't understand that you want to explain for me, sorry�, i don't understand the interest�
In which case i will have a file just with -n\n as content ?