как вставить текст в начало каждого абзаца в bash

как вставить текст в начало каждого абзаца в bash

У меня есть файл с несколькими абзацами, разделенными пустой строкой. Технически это не абзацы, а просто разделы текста, разделенные пустой строкой.

Я хочу пронумеровать абзацы, так сказать, вставив номер в первую строку каждой строки после пустой строки. Так что если в моем файле написано:

Это текст.
Это еще один текст.
Еще больше текста!

Это текст во втором разделе.
Еще немного текста.
Вы поняли...

Я хочу, чтобы он сказал:

1Это текст
это больше текста
Еще больше текста!

2Это текст во втором разделе.
Еще немного текста.
Вы поняли...

решение1

Попробуйте сделать это с помощью встроенных команд bash:

#!/bin/bash

l=1                          # paragraph counter
echo -n $l                   # print paragraph counter without new line
while read x; do             # read current line from file, see last line
  if [[ $x == "" ]]; then    # empty line?
    echo                     # print empty line
    read x                   # read next line from file, see last line
    ((l++))                  # increment paragraph counter
    echo -n $l               # print paragraph counter without new line
  fi
  echo "$x"                  # print current line
done < file

решение2

В общем, использование оболочки для разбора текста очень медленное и громоздкое. Вот еще несколько вариантов:

  1. Perl в «режиме абзаца»

    perl -00pe 's/^/$./' file 
    

    Объяснение

    Включает -00режим абзаца, где "строки" определяются последовательными \n\n, абзацами другими словами. s/^/$./Заменяет начало строки ( ^) текущим номером "строки" (абзаца) $.. -pСообщает Perl, что нужно печатать каждую строку входного файла после запуска скрипта, указанного -eв .

  2. Авк

    awk -vRS='\n\n' -vORS='\n\n' '{print NR$0}' file
    

    Объяснение

    -vRS='\n\n'устанавливает разделитель записей awk на последовательные символы новой строки. Как и в режиме абзаца perl, это заставляет его обрабатывать абзацы как «строки». Затем мы говорим ему вывести номер текущей строки ( NR) и текущую «строку» $0. -vORS=Устанавливает разделитель выходных записей на последовательные символы новой строки, чтобы абзацы также разделялись пустыми строками в выводе. Обратите внимание, что это добавит 2 пустые строки в конец вывода. Чтобы избежать этого, вы можете использовать head:

    awk -v RS='\n\n' -vORS='\n\n' '{print NR$0}' file | head -n -2
    

Для сравнения, вот время, которое потребовалось различным решениям на моей системе при запуске на тестовом файле размером 10 МБ:

$ time a.sh > /dev/null ## a.sh is Cyrus's solution

real    0m1.419s
user    0m1.308s
sys     0m0.104s

$ time perl -00pe 's/^/$./' file  > /dev/null 

real    0m0.087s
user    0m0.084s
sys     0m0.000s

$ time awk -v RS='\n\n' -vORS='\n\n' '{print NR$0}' file | head -n -2 >/dev/null

real    0m0.074s
user    0m0.056s
sys     0m0.020s

Как вы можете видеть выше, решения perl и awk на порядок быстрее подхода с использованием оболочки.

Связанный контент