bash условный getline с помощью awk / tr / sed? - PullRequest
0 голосов
/ 16 сентября 2018

Я борюсь с этим, я хочу объединить группу строк в одну строку / строку. Каждая строка (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. Поэтому я искал на форуме, нашел ли я пример и сделал это с помощью getline, подобного этому:

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

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

Ответы [ 5 ]

0 голосов
/ 17 сентября 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

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

0 голосов
/ 16 сентября 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 в тех редких случаях, когда это уместно.

0 голосов
/ 16 сентября 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
0 голосов
/ 16 сентября 2018

Эта программа должна выглядеть так:

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. строка больше не начинается с цифры (флаг установлен): начать заново (очистить буфер и флаг)
0 голосов
/ 16 сентября 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
...