bash условный getline с awk/tr/sed?

Я борюсь с этим, я хочу объединить группу строк в одну строку/строку. Каждая строка (titi/toto/tata) моего файла имеет 2 или 3 поля, разделенные знаком «;». Итак, мой ввод таков:

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

Мне нужен этот вывод:

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

Итак, вы можете видеть, что первые 3 строки представляют собой информацию (toto/tata и т. д.), которая должна повторяться для каждой строки после этого, начиная с числа.

Сначала в моем вводе была только одна строка с номером, поэтому это была группа 4 на 4. Поэтому я искал на форуме, нашел ли я пример, и сделал это с помощью такой строки:

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

Но затем у меня появилось 2 или даже 3 линии с числами... Поэтому я изо всех сил пытаюсь сделать «условный», который понимает, что он должен повторять первые 3 линии каждый раз, когда видит линию, начинающуюся с цифр.


person O.Wolf    schedule 16.09.2018    source источник
comment
Спасибо, сразу посмотрю.   -  person O.Wolf    schedule 16.09.2018


Ответы (5)


Эта программа должна так:

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

Объяснение:

  1. /^[^0-9]/{b=b$0";"}
  2. /^[0-9]/{print b$0;f=1}
  3. f&&/^[^0-9]/{b="";f=0}
  1. строка не начинается с цифры: собрать ввод (titi,toto,tata)
  2. строка начинается с номера: вывести собранные строки и $0, установить флаг
  3. строка больше не начинается с цифры (установлен флаг): начать сначала (очистить буфер и флаг)
person steffen    schedule 16.09.2018

Не могли бы вы попробовать следующее.

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

Решение 2-е: Если ваша Input_file может иметь последнюю строку как tot и т. д., и вы хотите распечатать ее, используйте следующее.

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
person RavinderSingh13    schedule 16.09.2018

$ 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

напишите свой исходный сценарий — см. http://awk.freeshell.org/AllAboutGetline, почему бы не использовать getline для этой (или большинства других ситуаций) и как правильно вызывать getline в тех редких случаях, когда это уместно.

person Ed Morton    schedule 16.09.2018

Вы можете попробовать этот awk:

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

И более понятно

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

Это может сработать для вас (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

Используйте пространство удержания для хранения первой части каждой записи. Когда встречается конечная часть записи, добавьте пробел, переставьте последнюю часть так, чтобы она следовала за первой частью, удалите первую новую строку и замените оставшиеся новые строки точкой с запятой. Распечатайте запись и, если следующая строка является конечной частью записи, повторите. В противном случае очистите пространство для хранения и добавьте текущую строку в пространство для хранения.

person potong    schedule 17.09.2018