O.Wolf
O.Wolf

Reputation: 55

bash conditionnal getline with awk/tr/sed?

I'm struggling with this, i want to concatenate a group of lines into a single one line/row. Each line (titi/toto/tata) of my file has 2 or 3 fields separated by a ";" So my input is like this:

titi1
titi2 
titi3
43;75;97
1;2;87
toto1
toto2
toto3
40;50;60
tata1
tata2
tata3
4;5;2
5;3;7
2;5;9

I need this output :

titi1;titi2;titi3;43;75;97
titi1;titi2;titi3;1;2;87
toto1;toto2;toto3;40;50;60
tata1;tata2;tata3;4;5;2
tata1;tata2;tata3;5;3;7
tata1;tata2;tata3;2;5;9

So has you can see the first 3 lines are informations (toto/tata etc...) that should be repeated for each line after that start with a number.

First my input had only one line with number so it was a grouping 4 by 4. so i searched in the forum had i found an example and did this with a getline like this :

awk '{getline b; getline c; getline d;printf("%s %s %s %s\n",$0,b,c,d)}'

But then i started to have 2 or even 3 lign with numbers... So i'm struggling doing a 'conditionnal' that understand that it should repeat the first 3 lign everytime it sees a lign starting with a numbers.

Upvotes: 4

Views: 125

Answers (5)

potong
potong

Reputation: 58478

This might work for you (GNU sed):

sed -r '/;/{:a;G;s/([^\n]*)\n(.*)/\2\n\1/;s/.//;s/\s*\n/;/g;n;/;/ba;x;z;x};H;d' file

Use the hold space to store the first part of each record. When an end part of a record is encountered, append the hold space, rearrange the last part to follow the first part, remove the first newline and replace the remaining newlines by semi-colons. Print the record and if the next line is an end part of a record repeat. Otherwise, clear the hold space and append the current line to the hold space.

Upvotes: 1

steffen
steffen

Reputation: 17028

This program should so:

awk 'f&&/^[^0-9]/{b="";f=0} /^[^0-9]/{b=b$0";"} /^[0-9]/{print b$0;f=1}'

Explanation:

  1. /^[^0-9]/{b=b$0";"}
  2. /^[0-9]/{print b$0;f=1}
  3. f&&/^[^0-9]/{b="";f=0}
  1. line does not start with a number: collect input (titi,toto,tata)
  2. line starts with number: print collected lines and $0, set flag
  3. line does not start with a number any more (flag is set): start over (clear buffer and flag)

Upvotes: 1

Ed Morton
Ed Morton

Reputation: 204074

$ awk -F';' 'NF>1{print s $0; p=1; next} p{s=p=""} {s=s $0 FS}' file
titi1;titi2;titi3;43;75;97
titi1;titi2;titi3;1;2;87
toto1;toto2;toto3;40;50;60
tata1;tata2;tata3;4;5;2
tata1;tata2;tata3;5;3;7
tata1;tata2;tata3;2;5;9

wrt your original script - see http://awk.freeshell.org/AllAboutGetline for why not to use getline for this (or most other situations) and how to call getline correctly on those rare occasions when it is appropriate to do so.

Upvotes: 2

ctac_
ctac_

Reputation: 2491

You can try this awk :

awk -F';' 'NF==1{if(b){a=b=""};a=a$0FS;next}{b=1;$0=a$0}1' infile

And more understandable

awk -F ';' '
  NF==1 {
    if ( b ) {
      a = b = "" 
    }
    a = a $0 FS 
    next
  }
  {
    b = 1
    $0 = a $0
  } 1
' infile

Upvotes: 1

RavinderSingh13
RavinderSingh13

Reputation: 133650

Could you please try following.

awk '
{
  sub(/ +$/,"")
}
/^[a-zA-Z]+/{
  if(val && flag){
    val=""
  }
  val=val?val ";" $0:$0
  flag=""
  next
}
{
  flag=1
  print val ";" $0
}'  Input_file

Solution 2nd: In case your Input_file could have last line as tot etc and you want to print it too then use following.

awk '
{
  sub(/ +$/,"")
}
/^[a-zA-Z]+/{
  if(val && flag){
     val=""
  }
  val=val?val ";" $0:$0
  flag=""
  next
}
{
  flag=1
  print val ";" $0
}
END{
  if(val && !flag){
     print val
  }
}'  Input_file

Upvotes: 2

Related Questions