Extrai uma substring com sed que pára na primeira ocorrência do fim

3

Eu tenho uma string onde eu preciso extrair uma substring, mas o fim da minha regex é repetido. Eu gostaria de sed para parar na primeira instância do fim do meu regex, muito parecido com funções instr () em muitas linguagens retornar a primeira instância. Exemplo:

echo "This is a test some stuff I want string junk string end" | sed -n 's/.*\(.te.*ng\).*//p' 
returns: test some stuff I want string junk string
I want to return: test some stuff I want string
    
por Ethan 27.05.2017 / 22:25

5 respostas

1
abordagem

grep (requer suporte PCRE ):

s="This is a test some stuff I want string junk string end"
grep -Po 'te.*?ng' <<< $s

Abordagem alternativa perl :

perl -ne 'print "$&\n" if /te.*?ng/' <<< $s

A saída (para ambas as abordagens):

test some stuff I want string
  • .*? - ? aqui é o modificador não-ganancioso , diz para combinar em moda mínima
por 27.05.2017 / 22:44
1

Faça isso em duas etapas: primeiro remova o prefixo (caso o terminador esteja presente no prefixo) e remova tudo após o prefixo. Use o comando T para pular uma linha se ela não corresponder:

echo "This is a test some stuff I want string junk string end" |
sed -n 's/.*\(.te.*ng\)//; T; s/\(ng\).*//p'

Como alternativa, exclua as linhas não correspondentes primeiro e, em seguida, execute a substituição como quiser.

echo "This is a test some stuff I want string junk string end" |
sed '/.*\(.te.*ng\)/!d; s/.*\(.te.*ng\)//; s/\(ng\).*//'

Como alternativa, execute as substituições e a impressão final apenas nas linhas correspondentes.

echo "This is a test some stuff I want string junk string end" |
sed '/.*\(.te.*ng\)/ { s/.*\(.te.*ng\)//; s/\(ng\).*//p; }'
    
por 28.05.2017 / 01:10
0

Eu sugiro usar o comando cut no seu caso

echo "I am a useful and I am a string. Did I mention that I'm a string?" | cut -d "string" -f1

Isso cortaria o corte da corda em três partes (antes da primeira, depois da 2. E entre a 'corda') com -d "" você pode escolher o padrão que você quer usar como cortador e com -fNúmero que você escolher qual parte tomar. Problema: a 'string' será removida Solução:

String='echo "I am a useful and I am a string. Did I mention that I'm a string?" | cut -d "string" -f1'
String="$(String) string"
echo $String

Adiciona a "string" do delimitador que foi removida para o final da variável $ String que foi definida com a saída

    
por 27.05.2017 / 22:35
0

A steeldriver apontou corretamente a correspondência não-gulosa com o SEL regex (emular o perl. *?) onde John1024 afirma claramente:

Sed regexes match the longest match. Sed has no equivalent of non-greedy.

Assim, há duas maneiras alternativas que podemos usar para contornar o problema. Primeiro, use o que realmente tem correspondência não-gananciosa, como perl :

$ str="This is a test some stuff I want string junk string end"
$ perl -pe 's/^.*(te.*?ng).*//' <<<  "$str"                                                                            
test some stuff I want string

Como alternativa, você poderia dar ao sed mais contexto para agrupar a correspondência, ou seja, adicionar o que vai seguir a primeira palavra "string":

$ sed -r 's/^.*(te.*?ng)\ junk.*//' <<<  "$str"                                                                        
test some stuff I want string
    
por 28.05.2017 / 01:54
0

# Como realizar a correspondência desejada: "test. *? string" usando o POSIX sed

sed -e '
   /test.*string/!d;      # non-interesting line
   /^test/s/string/&\
/;                        # append marker after the first substring "string"
   /\n/{P;d;}             # initial portion of pattern space is our result
   s/test/\
&/;D;                     # remove portion before the substring "test"
' yourfile

Outro método POSIX - ly é remover a string "string", 1 de cada vez, do final do espaço padrão, até que haja apenas uma esquerda ( após o "teste" de substring). Então o que resta é trazer o "teste" da substring à tona:

sed -e '
   :loop
      s/\(test.*string\).*string.*//
   tloop
   /^test/!s/test/\
&/;/\n/D
' yourfile
    
por 28.05.2017 / 11:09