Вы можете использовать tr
для преобразования потока в поток, который вы можете нормально обрабатывать:
stream | tr 'x\n' '\0x' | grep -qz xxx
Это превращает все x
байты в нулевые байты, а все байты перевода строки — в x
s, которые можно извлечь как обычно. То есть он перемещается на один шаг по пути перевода строки -> x -> null, поэтому последовательность из трех переводов строки теперь будет последовательностью из трех x
s, и никакие другие x
байты не появятся (они станут нулевыми, завершающими строками дляgrep
).
Это работает с POSIX tr
, но grep -z
является расширением. Вам может это не нужно -поведение разделения здесь не требуется -и большинство grep
s будут обрабатывать двоичные данные, но POSIX grep
требуется только для работы с текстовые файлы , так что вы так или иначе будете зависеть от расширения.
Если ваши настоящие данные представляют собой текстовый файл или просто не зависят от -безопасного поведения двоичных файлов, вы, вероятно, сможете выжить только
stream | tr 'x\n' '\nx' | grep -q xxx
-, то есть просто поменять местами два байта. Это почти POSIX -совместимо, но, вероятно, будет работать на практике почти везде (проблема в том, что последняя строка не будет завершена правильно, поэтому это не текстовый файл,так что grep
не обязательно принимать его).
Одна из возможных проблем в любом случае заключается в том, что файл без существующих x
байтов будет рассматриваться как одна очень длинная строка, которая может превысить ограничения, которые может обработать ваша grep
реализация. Выбор другого ожидаемого от -до -общего байта -может обойти это.
Я был удивлен, что ваша первоначальная команда grep -qz $'\n\n\n'
не работала, но у меня была ложная-положительная проблема для меня -она вела себя как grep -qz ''
и всегда совпадала. Я не уверен, почему это так.
Раздел BEGIN
выполняется до открытия любого входного файла, поэтому запуск for loop
не принесет вам пользы, так как первая строка ввода еще не прочитана, поэтому вы не знаете, сколько там полей. должны зациклиться. Если вы не добавите getline
, но это совсем другая банка червей (, см.http://awk.freeshell.org/AllAboutGetline).
Я бы позволил awk
создать содержимое полей, а затем позволить column
отформатировать его для интервалов, например.:
$ awk '
NR==1 { for (i=1; i<=NF; i++) printf " %s", i; print "" }
{ print NR, $0 }
' file | column -s' ' -t
1 2
1 a b
2 b c
3 c d
Если ваш входной файл может содержать несколько пробелов или табуляций между полями, просто измените последнюю строку awk-скрипта с { print
на { $1=$1; print
.
Вы можете использовать цикл for для перебора полей. NR — номер текущей строки, NF — количество полей в этой конкретной строке.
{ printf ("%4d", NR);
for (f = 1; f <= NF; ++f) printf (" %-6s", $f);
printf ("\n");
}
Для заголовка вам нужно дождаться первой строки, чтобы узнать, сколько столбцов вам нужно пометить. Итак, это идет перед предыдущим кодом. Обратите внимание, что в качестве метки выводится само f, а не $f, представляющее содержимое поля.
NR == 1 { printf ("%4d", NR);
for (f = 1; f <= NF; ++f) printf (" %-6s", f);
printf ("\n");
}
Вам нужно найти максимальную ширину поля, чтобы сохранить выравнивание. Каждый % -6s означает «строковое поле, выровненное по левому краю и дополненное пробелами до 6 символов».
Отредактируйте :для более продвинутой версии, вы можете хранить все данные в массиве 2 -D, проиндексированном [NR, NF], и выводить их в блоке END. Затем вы можете сделать еще две вещи:
(1 )Для каждого столбца найдите максимальную ширину любой ячейки и зафиксируйте формат % -10 с фактической шириной для этого столбца.
(2 )Для каждого столбцаесли он имеет все числовые значения, исправьте его %s вправо -, чтобы выровнять значения.
Мы можем генерировать таблицы, используя оболочку groff tbl
, которая генерирует код groff для создания таблиц в соответствии с требуемой архитектурой.
Здесь на основе данных мы динамически генерируем код для утилиты tbl, которая должна генерировать код для утилиты набора текста groff, используя утилиту awk:
< file \
awk '
BEGIN {
OFS = "@"
print ".TS"
print "box,tab(", ");"
}
!NF {next}
NR==1 {
fx(" ", "c", "c", ".")
fx(OFS)
}
{ $1 = NR OFS $1 };1
END { print ".TE" }
function fp(str, sep) {
printf "%s%s", sep, str
}
function fx(sep, a, b, c, i) {
fp(a)
for (i=1; i<=NF; i++)
fp(b""?b:i, sep)
fp("\n", c)
}
' - | tbl - | groff -Tascii | grep.
Выход:
+----------+
| 1 2 |
|1 A B |
|2 B C |
|3 C D |
+----------+