Пилаздесьспособ использования sed для получения текста между двумя другими строками в строке, например:
sed 's/.*starting_text\(.*\)ending_text.*/\1/'
но мне нужна простая команда (вроде tr
, но для извлечения строк), которая просто брала бы две строки и обрезала бы все до первой строки или после второй строки, например
grep something some_file | between message\"\:\" " with"
и будет обрабатывать экранированные символы.
решение1
Если разделители встречаются несколько раз в строках, можно использовать Perl, например:
between() {
perl -Tlne 'BEGIN{$b=shift;$e=shift}
print for /\Q$b\E(.*?)\Q$e\E/g' "$@"
}
И тогда, например:
$ echo "[b]test[e] foo [b]bar[e]" | between '[b]' '[e]'
test
bar
Вы также можете использовать его как:
between BEG END file1 file2...
решение2
Выполнение этого в sed в общем случае потребовало бы экранирования символов в регулярном выражении, используемом для поиска подстроки, которую я нашелздесь(примечание: дополнительная информацияздесьесли у вас возникнут проблемы).
Затем я нашел, как передать данные в функциюздесь.
Объединяя все это в функцию, которую я могу использовать в своем коде .bashrc
, я получаю следующее (хотя мне не нужно задавать переменные a и b, но так легче читать):
between(){
a=$(printf '%s\n' "$1"|sed 's![\*.^$/[]!\\&!g')
b=$(printf '%s\n' "$2"|sed 's![\*.^$/[]!\\&!g')
sed "s/.*$a\(.*\)$b.*/\1/"
}
как сказал Джозеф Р.,этот ответпоказывает, как использовать grep -oP, чтобы сделать то же самое. Чтобы избежать Perl-совместимого регулярного выражения, я нашелэтот, поэтому, возможно, следующее также сработает:
between(){
a=$(printf '%s\n' "$1"|sed 's![]\*.^+?(){|$[]!\\&!g')
b=$(printf '%s\n' "$2"|sed 's![]\*.^+?(){|$[]!\\&!g')
grep -oP "(?=$a).*?(?=$b)"
}