sed print flag

I have an input file that looks something like this:

....
key1: ABC
....
key2: DEF
....
key1: GGG
....
key2: HHH
....

The row of dots represents any number of lines that don't contain the strings "key1:" or "key2:" The strings key1: and key2: will always appear alternately as in the above example.

The sed command:

sed -n -e 's_key1: \(...\)_\1_p' -e 's_key2: \(...\)\1_p'

produces this output:

ABC
DEF
GGG
HHH

But what I really want is this output:

ABC DEF
GGG HHH

At one point I thought there was a upper case P flag that would print without
the newline character. That would do it, but at least with my GNU sed version 4.2.1 I don't see such a flag.

Are there any other simple ways to modify my sed command to produce the desired output?

Hello pmennen,

Welcome to forums, please use code tags for commands/codes/Inputs which you are using in your posts as per forum rules. You could try following an awk solution.

awk '/key1/{A=A?A OFS $2:$2} /key2/{B=B?B OFS $2:$2} END{print A ORS B}'  Input_file

Output will be as follows.

ABC GGG
DEF HHH

Off course it will work only for keywords key1 and key2 as per your shown input, if you have more conditions please do let us know.

Thanks,
R. Singh

Thanks R. Singh (and sorry for forgetting the code tags).

Yes, I did simplify the problem somewhat for brevity, so I will probably have to learn at least some of that arcane looking awk syntax. (I realize that sed is just as arcane, its just that I am already familiar with it).

It seems like this may be simple enough a sed solution might be possible without resorting to overly cryptic methods. If anyone knows of such a solution, I would still be interested in seeing it.

Thanks
~Paul

GNU sed might handle a newline character like this

sed -n '
s_key1: \(...\)\n_\1_p
s_key2: \(...\)_\1_p
'

(Untested.)

This at least works in GNU sed

mute@tiny:~$ sed -n '/key1:/{s/key1: //;h};/^key2:/{H;x;s/\nkey2://p}' input
ABC DEF
GGG HHH

Place it in hold space. Append key2 to hold space, swap hold/pattern space, then remove new line and key2: . Might need to fold spaces.

2 Likes

Another option:

sed -n 's/key[12]: //p' file | paste -d" " - - 

--
( or sed -n 's/key[12]: \(...\)/\1/p' file | paste -d" " - - if you will )

---

That will not work since even in GNU sed, the trailing newline will be chopped off before the line gets processed, so the substitute command will never "see" it..

3 Likes

My actual input file was a bit more complicated, and was similar to this:

....
??? key1: word1, word2, word3, word4
....
????? key2: word5, word6, word7
....
?????? key1: word8, word9
....
??????? key2: word10, word11
....

And the desired output is:

word1 word5
word8 word10

Before the reply from neutronscott came in, I managed to produce the desired output by piping it to a separate sed command to remove the unwanted newlines (which is somewhat similar to the solution suggested by Scrutinizer using paste):

sed -n -r -e "s_.* key1: ([^,]*).*_\1_p" -e "s_.*key2: ([^,]*).*_\1_p" input.txt | sed "N;s/\n/ /"

Using the method suggested by neutronscott, I'm now producing the same output using:

sed -n -r "/key1:/{s/.* key1: ([^,]*).*/\1 /;h};/key2:/{H;x;s/\n.* key2: ([^,]*).*/\1/p}" input.txt

It's actually slightly longer, but I prefer a single call to sed when possible.

Thanks everyone for your replies!

~Paul

Slightly shorter:

sed -n 's/,.*$//; /key1/h; /key2/{H; x; s/^[^:]*: //; s/\n[^:]*://; p} ' file
word1 word5
word8 word10

---------- Post updated at 08:05 ---------- Previous update was at 08:04 ----------

And Scrutinizer's approach will become

sed -n 's/^.*key[12]: \|,.*$//gp' file | paste -d" " - -

And taking an idea from your 2nd example we get two more equivalent versions that are still slightly shorter:

sed -n 's/,.*//; /key1/h; /key2/{H; x; s/^[^:]*: \|\n[^:]*://gp}' file

sed -n '/key1/h; /key2/{H; x; s/,[^\n]*\|^[^:]*: \|\n[^:]*://gp}' file

which possibly might even be as short as you can get using a non piped single call to sed.

~Paul