Único comando que usa duas strings para extrair string entre elas, como 'tr' (sem expressões)

5

Vimos aqui uma maneira de usar sed para obter texto entre duas outras strings em uma linha, como:

sed 's/.*starting_text\(.*\)ending_text.*//'

mas eu gostaria de um comando simples (como tr , mas para extração de string) que apenas usou duas strings e cortaria 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.

    
por Gary S. Weaver 27.09.2013 / 19:42

2 respostas

8

Se os delimitadores podem aparecer várias vezes por linhas, você poderia usar o perl como:

between() {
  perl -Tlne 'BEGIN{$b=shift;$e=shift}
             print for /\Q$b\E(.*?)\Q$e\E/g' "$@"
}

E, por exemplo, 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...
    
por 27.09.2013 / 20:54
2

Fazer isto em sed genericamente exigiria caracteres de escape no regexp usado para encontrar a substring que eu encontrei aqui (nota: mais informações aqui se você tiver problemas) .

Depois, descobri como canalizar para uma função aqui .

Colocando tudo isso em uma função que eu possa usar no meu .bashrc , parece que (embora eu não precise definir o a e b vars, 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.*//"
}

como Joseph R. mencionou, esta resposta mostra como usar grep -oP para fazer semelhante. Para escapar do regexp compatível com Perl, encontrei este , 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)"
}
    
por 27.09.2013 / 19:42