Serraaquiuma maneira de usar sed para obter texto entre duas outras strings em uma linha, como:
sed 's/.*starting_text\(.*\)ending_text.*/\1/'
mas eu gostaria de um comando simples (como tr
, mas para extração de string) que pegasse apenas duas strings e cortasse tudo antes da primeira string ou depois da segunda string, por exemplo
grep something some_file | between message\"\:\" " with"
e lidaria com caracteres de escape.
Responder1
Se os delimitadores aparecerem várias vezes por linha, você poderá usar perl como:
between() {
perl -Tlne 'BEGIN{$b=shift;$e=shift}
print for /\Q$b\E(.*?)\Q$e\E/g' "$@"
}
E então, por exemplo:
$ echo "[b]test[e] foo [b]bar[e]" | between '[b]' '[e]'
test
bar
Você também pode usá-lo como:
between BEG END file1 file2...
Responder2
Fazer isso no sed genericamente exigiria caracteres de escape no regexp usado para encontrar a substring que encontreiaqui(nota: mais informaçõesaquise você tiver problemas).
Então, descobri como canalizar para uma funçãoaqui.
Juntar tudo isso em uma função que posso usar no meu .bashrc
, parece (embora eu não precise definir os vars a e b, mas facilita a leitura):
between(){
a=$(printf '%s\n' "$1"|sed 's![\*.^$/[]!\\&!g')
b=$(printf '%s\n' "$2"|sed 's![\*.^$/[]!\\&!g')
sed "s/.*$a\(.*\)$b.*/\1/"
}
como Joseph R. mencionou,esta respostamostra como usar grep -oP para fazer algo semelhante. Para escapar do regexp compatível com Perl que encontreiesse, então talvez o seguinte também funcione:
between(){
a=$(printf '%s\n' "$1"|sed 's![]\*.^+?(){|$[]!\\&!g')
b=$(printf '%s\n' "$2"|sed 's![]\*.^+?(){|$[]!\\&!g')
grep -oP "(?=$a).*?(?=$b)"
}