А вот более общий подход, не зависящий от количества файлов с sed
:
sed '1{x;s/$/_/;x;}
/foo/{x;s/_/ 0_/g;x;}
G;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\30_\4\1\3\2_/
$! {h;d;}
s/[^_]*_//
y/_/\n/' file*
Это зависит от каждого файла, начинающегося со строки foo
, как в вашем примере.
Учитывая, что у вас есть базовые знания о том, как работает sed
, пространство шаблонов и пространство хранения, вот объяснение:
Основная идея состоит в том, чтобы построить всю выходную таблицу в пространстве хранения. В каждой строке пространство хранения содержит таблицу в этой точке вместе со строкой шаблона, необходимой для новых строк. Мы используем _
в качестве разделителя строк во время обработки. А теперь шаг за шагом:
1{x;s/$/_/;x;}
Это инициализирует пространство удержания с помощью одного _
в качестве начала строки нашего шаблона.
/foo/{x;s/_/ 0_/g;x;}
/foo/
адресует строки, содержащие foo
, что указывает на начало нового файла. В этом случае выполняются команды в {}
: Каждая строка в области хранения (фактические строки таблицы и строка шаблона) добавляется 0
. Если позже мы встретим ключевое слово этой строки, 0
заменится правильным числом; если ключевое слово не встречается, остается 0
.
G;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
'G' добавляет пространство удержания к пространству шаблона. Команда s
состоит из четырех разделов \(\)
: первый содержит ключевое слово, второй — значение, третий — все после новой строки (так что это таблица, добавленная из пробела). ) до второго вхождения ключевого слова (обратная ссылка \1
). Четвертый содержит все в этой строке, кроме последнего 0
.Итак, мы нашли уже существующую строку с этим ключевым словом и заменили 0
. Мы опускаем все до новой строки и просто сохраняем обновленную таблицу.
s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\30_\4\1\3\2_/
Еще одно совпадение, включающее символ новой строки \n
, поэтому мы знаем, что не нашли ключевое слово в таблице (иначе в предыдущей строке был бы удален символ новой строки). Поэтому на этот раз мы добавляем новый строку в конец, состоящую из ключевого слова, строки шаблона и значения. И вот фокус со строкой шаблона: мы добавили в нее один столбец 0
для каждого нового файла, поэтому, если мы удалим один 0
у нас есть столбец 0
для каждого файла, где это ключевое слово не существовало.
$! {h;d;}
Если это была не последняя строка, переместите измененную таблицу обратно в место хранения (h
) и начать сначала (d
).
s/[^_]*_//
Для последней строки это удаляет строку шаблона.
y/_/\n/
И это заменяет _
на новой строки. Кроме того, вы также можете заменить пробелы табуляцией, если хотите.
Редактировать
Если предположение о том, что каждый файл начинается со строки foo
, неверно, нам нужен другой метод для скажи sed
wh en начинается новый файл, например, добавляется дополнительная строка для каждого запуска файла и передается все это в sed
:
for file in file*; do
echo Start of $file
cat $file
done | sed '1{x;s/$/__/;x;}
/Start of/{G;s/_/ 0_/g;s/Start of \(.*\)\n\([^_]*\)_\([^_]*\) 0/\2_\3 \1/;x;d;}
G;l;s/^\([a-z]*\) *\([0-9]*\).*\n\(.*_\)\1\([^_]*\)0/\3\1\4\2/
l;s/^\([a-z]*\) *\([0-9]*\).*\n\([^_]*\)0_\(.*\)/\3 0_\4\1\3\2_/
$! {h;d;}
s/[^_]*_//
y/_/\n/'
Эта версия также генерирует верхнюю строку таблицы со всеми именами файлов в качестве заголовков столбцов.