Использование одного вызова sed для заголовка первых строк H и хвоста последних строк T - PullRequest
0 голосов
/ 23 февраля 2019

Я некоторое время назад написал программу на C, чтобы подвести итог текстового файла, выполнив одновременно и head, и tail, только с одиночным чтением из piped вход.Пример:

$ headtail -h 3 -t 3 < /tmp/x10
line01
line02
line03
... 4 output lines omitted ...
line08
line09
line10

Это работает, но я чувствую себя грязно из-за отсутствия изящного псевдонима sed, который может это сделать.Найдя этот SO-ответ, который использует от sed до печати последних N строк , теперь это кажется достижимым, но я не совсем там.

Например, отдельный headи tail работа:

$ sed -n -e '1,3p' < /tmp/x10
line01
line02
line03

$ sed -n -e ':a; $p; N; 4,$D; ba' < /tmp/x10
line08
line09
line10

Но моя попытка объединить два не удалась:

$ sed -n -e '1,3p; :a; $p; N; 4,$D; ba' < /tmp/x10
line01
line08
line09
line10

Было бы неплохо, если бы он работал, если H + T > N строк в файле (действует как cat), а также для печати разделителя, указывающего, что некоторые строки были опущены из середины (число пропущенобыло бы неплохо, но я мог бы жить без него).

Ответы [ 3 ]

0 голосов
/ 23 февраля 2019

Нет необходимости в C-программах или замысловатых сценариях sed, все, что вам нужно, - это понятный, простой, переносимый, эффективный сценарий awk:

$ seq 10 | awk -v h=3 -v t=3 'NR<=h; {a[NR%t]=$0} END{for (i=1; i<=t; i++) print a[(NR+i)%t]}'
1
2
3
8
9
10

$ seq 10 | awk -v h=3 -v t=3 'NR<=h; {a[NR%t]=$0} END{print "skipped", NR-(t+h); for (i=1; i<=t; i++) print a[(NR+i)%t]}'
1
2
3
skipped 4
8
9
10

Вы не сказали, какие у вас требования, если диапазоныперекрытие, поэтому я просто включаю перекрывающиеся линии в обеих выходных секциях и печатаю отрицательное значение для пропущенного, например:

$ seq 10 | awk -v h=7 -v t=5 'NR<=h; {a[NR%t]=$0} END{print "skipped", NR-(t+h); for (i=1; i<=t; i++) print a[(NR+i)%t]}'
1
2
3
4
5
6
7
skipped -2
6
7
8
9
10

, но каковы бы ни были ваши требования для крайних случаев, их было бы тривиально реализовать.

0 голосов
/ 23 февраля 2019

Это может работать для вас (GNU sed):

sed -E '1,5p;H;$!d;x;s/.*((\n[^\n]*){3})$/\1/;s/./==========&/' file

Это печатает первые пять и три последние строки, разделенные ==========.

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

Другое решение, менее интенсивное использование памяти, но ограниченное тем, что строки заголовков равны или меньше, чемследующие строки:

sed ':a;$!{N;;s/[^\n]\+/&/5;3{p;x;s/^/==========/p;x};Ta};$P;D' file

Здесь первые три и последние пять строк напечатаны с разделителем.

0 голосов
/ 23 февраля 2019

Попробуйте:

$ seq 10 | sed -n -e '1,3{p;b}; :a; $p; N; 7,$D; ba'
1
2
3
8
9
10

(* 7 получается из сложения вместе 3 (голова) плюс 3 (хвост) плюс 1.)

Если мыувеличив хвост с 3 до 7, мы получим весь файл:

$ seq 10 | sed -n -e '1,3{p;b}; :a; $p; N; 12,$D; ba'
1
2
3
4
5
6
7
8
9
10

(12 равен 3 (голова) плюс 7 (хвост) плюс 1.)

Как это работает

  • 1,3{p;b}

    Для любой из первых трех строк мы печатаем их (p), а затем ветвь (b) после остальной частиКоманды в коде.

  • :a; $p; N; 7,$D; ba

    Это работает так же, как и раньше , за исключением , что эти строки никогда не видят первые три строки.Следовательно, мы должны изменить начальную точку для команды D на 7.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...