extrai valor entre dois padrões de pesquisa na mesma linha

5

Eu tenho o seguinte em um arquivo Output.dat. Eu preciso extrair o valor entre dn: uid = e , ou =

 dn: uid=user1,ou=Active,ou=Member,dc=domain,dc=org
 dn: [email protected],ou=Active,ou=Member,dc=domain,dc=org
 dn: uid=usertest,ou=Active,ou=Member,dc=domain,dc=org
 dn: uid=abc1,ou=Active,ou=Member,dc=domain,dc=org

Eu tentei usar 'sed -e' / dn: uid = /, /, ou = / p 'output.dat mas retorna linha completa em vez de valor.

quando tentou usar sed -e '/dn: uid=/,/,ou=//p' output.dat , obteve o seguinte erro:

    sed: -e expression #1, char 18: unknown command: '\'
    
por Raza 21.05.2014 / 22:47

4 respostas

11

Se você tem uma versão do GNU grep com suporte a PCRE ( -P ), então assume que você quer dizer a ocorrência primeiro de ,ou

grep -oP '(?<=dn: uid=).+?(?=,ou=)' file

Se você quiser corresponder ao segundo ,ou , é possível remover o modificador ? não-ambicioso

grep -oP '(?<=dn: uid=).+(?=,ou=)' file

As expressões entre parênteses são asserções de comprimento zero (também conhecidas como lookarounds ), o que significa que elas fazem parte da correspondência, mas não são retornadas como parte do resultado. Você poderia fazer a mesma coisa nativamente em perl, por exemplo,

perl -ne 'print "$1\n" if /(?<=dn: uid=)(.+?)(?=,ou=)/' file 

É possível fazer algo similar em sed, usando o agrupamento regular (sem comprimento zero), por ex. (para o GNU sed - outras variedades podem precisar de escape adicional)

sed -rn 's/(.*dn: uid=)([^,]+)(,ou=.*)//p' file

ou simplificando ligeiramente

sed -rn 's/.*dn: uid=([^,]+),ou=.*//p' file

Observe que o [^,] é um truque aqui, já que o sed não tem uma opção de correspondência não voraz verdadeira.


> Afterthought : embora não seja exatamente o que você perguntou, parece que o que você realmente quer fazer é ler name=value pares separados por vírgulas de um arquivo e, em seguida, dividir ainda mais o valor do primeiro campo de seu nome. Você pode conseguir isso de muitas maneiras - incluindo

awk -F, '{sub(".*=","",$1); print $1}' file

ou uma solução pura como

while IFS=, read -r a b c d; do printf '%s\n' "${a#*=}"; done < file 
    
por 21.05.2014 / 22:59
4

Este é um bom trabalho para o awk. Você pode dividir a string em vez de tentar usar um regex. Aqui está uma solução:

$ awk -F= '{ split($2,arr,","); print arr[1]  }' test.txt
user1
[email protected]
usertest
abc1
    
por 21.05.2014 / 22:51
3

com sed :

sed 's/[^=]*=\([^,]\+\),.*//' file

Isso pressupõe que uid= terá a primeira ocorrência de = na linha e presume que você deseja parar na primeira ,ou= instância na linha.

Explicação

Isso procura por qualquer número de caracteres não = ( [^=]* ) seguido por = , em seguida, corresponde e salva tantas sem-vírgulas quanto possível ( \([^,]\+\) ) seguido por uma vírgula e o restante a linha ( ,.* ). Isso significa que ele substituirá tudo até e incluindo o primeiro = e após a primeira vírgula com qualquer caractere não-vírgula que encontrar após o primeiro = na linha.

    
por 21.05.2014 / 23:19
3

Mais algumas escolhas, por ordem de duração:

  1. GNU grep com PCREs

    grep -oP 'uid=\K[^,]+' file 
    

    O \K descarta tudo correspondido a esse ponto, que combinado com a opção -o fará com que grep imprima somente o trecho mais longo de caracteres que não são , que vem depois do uid= .

  2. awk

    awk -F'[=,]' '{print $2}' file 
    

    -F'[=,] define o separador de campo como = ou , , então o segundo campo é o nome de usuário.

  3. sed

    sed -r 's/.{8}([^,]*).*//' file 
    

    Isso corresponderá aos primeiros 7 caracteres ( .{7} ) = , capturará o trecho mais longo de não , como e substituirá a linha inteira por .

  4. perl

    perl -pe 's/.+?=([^,]+).*/$1/' file 
    

    O -pe significa "imprimir todas as linhas depois de aplicar o script dado por -e". O s/// é o operador de substituição e a expressão regular procura o primeiro ( .+? , o ? faz corresponder a sequência mais curta possível) = e, em seguida, captura o trecho mais longo de caracteres que não são , naquela. O s/// substitui o que foi correspondido com o que foi capturado (o que estava dentro dos parênteses).

  5. cut

    cut -d'=' -f 2 file | cut -d ',' -f 1 
    

    O -d define o delimitador como = , então o segundo ( -f 2 ) campo é username,ou . O segundo cut usa , como delimitador e imprime apenas o nome de usuário.

por 22.05.2014 / 02:40