Добавить «префикс блока» ко всем строкам, принадлежащим одному и тому же блоку файла

Команда printfиспользует свой первый аргумент в качестве формата для вывода последующих аргументов. printf %100sвыводит свои аргументы, дополненные до 100 символов шириной, используя пробелы (слева ). Для форматирования не предоставляется аргумент, поэтому он форматирует пустую строку один раз и выводит 100 пробелов. Вы можете видеть, что:

$ printf %100s | hexdump -C
00000000  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
00000064

(20 — шестнадцатеричный пробел; *означает повторение предыдущей строки)

В строках формата используются приблизительно спецификаторы C Xprintf:%, необязательная ширина для размещения отформатированного значения,и тип используемого формата. s— это форматирование строки, и строки по умолчанию дополняются пробелами слева. Может быть несколько форматов или других буквальных частей:printf "a%10sb\n" helloотпечатков

 a         xb.

trзаменяет выбранные символы в стандартном вводе выбранными заменами и выводит результат на стандартный вывод. tr " " "="содержит один символ для замены -пробелом -и один символ для замены на -знак равенства. Таким образом, он превращает каждый пробел во входных данных в =, а остальные оставляет без изменений. Вы тоже можете попробовать:

$ tr " " "="
hello world
hello=world

(Я набрал "привет, мир")

У вас может быть несколько замен:tr abc defпревращает a в d, b в e, c в f, а остальное оставляет без изменений. Здесь это всего лишь один символ, так как printfмог дешево сгенерировать именно его.

Конвейер |вызывает вывод команды слева, printf %100s, для использования в качестве ввода команды справа, tr " " "=". То есть в trдается сто последовательных пробелов, и каждый из них заменяется на =, при этом выводится новая строка.

printf %100s | tr " " "="
====================================================================================================

0
04.03.2021, 13:17
2 ответа

GNU sed работает в расширенном режиме регулярных выражений -Eплюс автопечать отключена -n, так что Мы знаем, когда печатать.

sed -En '
  #--------------------------------
  # printing the block in pattern space
  #--------------------------------
  /\n/{
    s/.*\n(.*)/\1&/
    P;/\n.*\n/D;$d;g
  }

  #--------------------------------
  # collect block
  #--------------------------------

  :15
  /^1/{
    N;h
    /\n5/!b15

    #--------------------------------
    # collect trailing 5 lines
    #--------------------------------
    :tail5
      $bend
      n
    /^5/{H;$!btail5;}

    #--------------------------------
    # place block prefix @ eol
    #--------------------------------
    $!x;$g
    :end
    s/.*\n3\t([^\n]+)\n.*/\n&\n\1\t/
    D; # take me to block print section
  }
' file

Результат:

bar1    1   foo1
bar1    2   foo1
bar1    3   bar1
bar1    4   foo1
bar1    5   foo1
bar2    1   foo2
bar2    2   foo2
bar2    3   bar2
bar2    4   foo2
bar2    4   foo3
bar2    5   foo2
bar2    5   foo3
0
18.03.2021, 22:27

В вашем случае на ум приходит решение с двумя -проходами awk(, что означает, что мы должны указать имя входного файла дважды в качестве операндов в строке команды -)]. Предполагается, что токены в строке разделены \tна входе и также должны быть разделены \tна выходе.

awk 'BEGIN{FS=OFS="\t"}
     NR==FNR{if ($1=="3") pre[++i]=$2;next} $1=="1" {j++} {print pre[j],$0}' input input

В первом проходе, гдеNR(глобальный счетчик строк )равенFNR(счетчику )на -строку файла -, мы заполняем массив preпрефиксами каждые раз мы встречаем строку с первым полем ($1), равным 3. Итак, pre— это сопоставление между «номером блока» и соответствующим префиксом. Кроме того, мы ничего не печатаем и сразу пропускаем выполнение к следующей строке.

Во втором проходе мы увеличиваем счетчик блоков jкаждый раз, когда находим условие «начало блока» (первое поле $1равное 1), и для всех строк добавляем префикс, соответствующий счетчик блоков.

3
18.03.2021, 22:27

Теги

Похожие вопросы