![Выбор раздела файла](https://rvso.com/image/164701/%D0%92%D1%8B%D0%B1%D0%BE%D1%80%20%D1%80%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%D0%B0%20%D1%84%D0%B0%D0%B9%D0%BB%D0%B0.png)
У меня есть файл, отформатированный следующим образом:
title1
line
line
title2
line
line
line
title3
line
line
и я хотел бы извлечь раздел ниже title2
и удалить отступ. В настоящее время я использую sed
(но awk
или скрипт оболочки был бы подходящим в моем контексте, к сожалению, не такие языки, как perl
или python
) вот так:
sed -n -e '/^title2$/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; s/^[ \t]*// ; p }'
но это оставляет логически пустую строку в конце (логически, потому что она может содержать пробелы или табуляции). Я хочу избавиться от нее. Обратите внимание, что в части, которую нужно сохранить, могут быть другие логически пустые строки (иначе a /^[ \t]*$/ d
сделал бы работу). Таким образом, я хотел бы получить такой результат:
line
line
line
Я могу сделать это с помощью дополнительного процесса sed -e '$d'
, но мне хотелось бы узнать, можно ли избежать этого второго процесса.
решение1
Я использовал место ожидания и в итоге получил
sed -ne '/^title2$/,/^[a-zA-Z]/ { /^title2$/ { n; h; b; } ; /^[a-zA-Z]/ d; H; x; s/[ \t]*//; P; s/.*\n//; x }'
который, похоже, правильно справляется с делами, которые мне интересны.
решение2
- если это «чистая» линия (без табуляции или белого цвета), удалите ее также с помощью
/^$/
для «логического» использования пробела
/^\s*$/
sed -n -e '/^title2:/,/^[a-zA-Z]/ { /^[a-zA-Z]/ d ; /^$/ d ; s/^[ \t]*// ; p }'
где
/^$/
начало и конец строки соответствия/^\s*$/
сопоставить начальную строку, ноль или больше пробелов или табуляций, конец строки
решение3
sed -n '/title2/,/^\S/ { //b; /^\s*$/ { N; /\n\S/q; P; D }; s/^\s*//; p }'
Я изначально сделал это, чтобы привлечь внимание @Archemar. Я был бы очень признателен, если бы вы моглипожалуйстаответить намой комментарий в этом постекогда у вас будет время. Даже если ответ "Я не знаю". СПАСИБО.
В моей оболочке bash, по крайней мере, это работает без -e
. Просто интересно, зачем это вообще нужно? И если\s
или\S
не поддерживается, вы можете заменить их на [ \t]
's и [^ \t]
's соответственно.
Разбор для тех, кто был таким же невежественным, как и я, когда впервые увидел этот вопрос:
-n
отключает автоматическую печать/title2/,/^\S/
диапазон дляsed
поиска (от строки, в которой впервые встречается строка "title2
", до следующей строки, которая начинается с символа, отличного от пробела[т.еtitle3
.]включительно){
просто означает применить вложенные команды к диапазону или шаблону, который я только что указал//b
позволяет следующим командам не применяться к началу и концу диапазона.
Более буквально, если вы сопоставляетеtitle2
или^\S
просто переходите к концу скрипта (b
) (обрабатываете следующую строку в файле, если таковые остались), потому что вГНУsed
(БСДговорит то же самое, не уверен, есть ли какая-то другая версияsed
)'//' повторяет последнее совпадение регулярного выражения
/^\s*$/
соответствует «логически пустым» строкам в диапазоне.{
N; /\n\S/q;
Таким образом, если это «логически пустая» строка,N
добавляет следующую строку в пространство шаблона, а затем, если эта следующая строка является следующим заголовком, обработка полностью прекращается (q
), поэтому ни «логически пустая» строка, ни следующий заголовок не печатаются.P; D
Если «логически пустая» строкане являетсяза которым следует следующий заголовок, затемтолькопечатается «логически пустая» строка (P
), а затемтолько«логически пустая» строка удаляется из пространства шаблона, оставляя следующую строку, которая была добавлена в пространство шаблона, дляN
обработки с начала скрипта (D
)
}
s/^\s*//; p
убирает пробелы и табуляции в начале строки и печатает отформатированную строку
}
@Archemar пожалуйстаПОМОЩЬ