У меня есть файл с несколькими абзацами, разделенными пустой строкой. Технически это не абзацы, а просто разделы текста, разделенные пустой строкой.
Я хочу пронумеровать абзацы, так сказать, вставив номер в первую строку каждой строки после пустой строки. Так что если в моем файле написано:
Это текст. Это еще один текст. Еще больше текста! Это текст во втором разделе. Еще немного текста. Вы поняли...
Я хочу, чтобы он сказал:
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
В общем, использование оболочки для разбора текста очень медленное и громоздкое. Вот еще несколько вариантов:
Perl в «режиме абзаца»
perl -00pe 's/^/$./' file
Объяснение
Включает
-00
режим абзаца, где "строки" определяются последовательными\n\n
, абзацами другими словами.s/^/$./
Заменяет начало строки (^
) текущим номером "строки" (абзаца)$.
.-p
Сообщает Perl, что нужно печатать каждую строку входного файла после запуска скрипта, указанного-e
в .Авк
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 на порядок быстрее подхода с использованием оболочки.