Команда 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 " " "="
====================================================================================================
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
В вашем случае на ум приходит решение с двумя -проходами 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
), и для всех строк добавляем префикс, соответствующий счетчик блоков.