Comando único usando duas strings para extrair string entre elas, como 'tr' (sem expressões)

Comando único usando duas strings para extrair string entre elas, como 'tr' (sem expressões)

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)"
}

informação relacionada