Use o awk / sed para remover tudo, exceto o padrão correspondente em uma coluna específica

1

Eu tenho um arquivo assim:

Text1 somethingAAxxxxxxxsomething,elseAAxxxxxxxfoo text1
Text2 somethingAAxxxxxxxsomething,elseAAxxxxxxxfoo text2
Text3 somethingAAxxxxxxxsomething,elseAAxxxxxxxfoo text3

O "algo", algo, mais e foo são letras / espaços / vírgulas aleatórias O AAxxxxxxx é o que eu quero corresponder. os X's são números e é sempre uma matriz de 7 números 0-9, por exemplo, AA0000001 ou AA9999999 . Desejo extrair apenas a parte AAxxxxxxx da coluna 2 para que minha saída seja:

Text1 AAxxxxxxx,AAxxxxxxx text1
Text2 AAxxxxxxx,AAxxxxxxx text2
Text3 AAxxxxxxx,AAxxxxxxx text3

Exemplo de entrada

Text1 somethingAA0123456something,elseAA6543210foo text1
Text2 somethingAA1234567something,elseAA7654321foo text2
Text3 somethingAA2345678something,elseAA8765432foo text3

Saída desejada

Text1 AA0123456,AA6543210 text1
Text2 AA1234567,AA7654321 text2
Text3 AA2345678,AA8765432 text3

Editar: algumas linhas contêm mais de 2 segmentos "AAxxxxxxx", por exemplo

Entrada

Text1 somethingAAxxxxxxxsomething,elseAAxxxxxxxfooblahAAxxxxxxx^blahblahAAxxxxxxx text1
Text2 somethingAAxxxxxxxsomething,elseAAxxxxxxxfooblahAAxxxxxxx^blah text2
Text3 somethingAAxxxxxxxsomething,elseAAxxxxxxxfoo text3

Saída desejada

Text1 AA0123456,AA6543210,AA1231252,AA1256712 text1
Text2 AA1234567,AA7654321,AA1926572 text2
Text3 AA2345678,AA8765432 text3
    
por Blaze 29.03.2017 / 22:59

5 respostas

2

sed pode fazer isso. Podemos usar 4 grupos correspondentes para encontrar o prefixo, sufixo e dois IDs no meio.

Código:

sed -rn 's/([^ ]+) .*(AA[0-9]{7}).*(AA[0-9]{7}).* ([^ ]+)/ , /p' file1

Dados de teste:

Text1 somethingAA0123456something,elseAA6543210foo text1
Text2 somethingAA1234567something,elseAA7654321foo text2
Text3 somethingAA2345678something,elseAA8765432foo text3

Resultados:

Text1 AA0123456,AA6543210 text1
Text2 AA1234567,AA7654321 text2
Text3 AA2345678,AA8765432 text3
    
por 29.03.2017 / 23:09
2

perl abordagem. Semelhante à abordagem sed . Teste a linha em relação a uma expressão regular longa, capturando as partes relevantes desejadas da linha em $ 1, $ 2, $ 3, $ 4. Construa uma resposta em $ _ para que seja impressa graças ao sinalizador '-p'.

$ perl -pe 'if(/^(Text\d+) .*(AA\d{7}).*(AA\d{7}).* (.*)/){$_="$1 $2,$3 $4$/"}' file1
Text1 AA0123456,AA6543210 text1
Text2 AA1234567,AA7654321 text2
Text3 AA2345678,AA8765432 text3
$
    
por 29.03.2017 / 23:26
2

solução awk:

$ a="Text1 somethingAA0123456something,elseAA9876543foo text1"
$ awk -F"[ ,]" '{match($2,/(AA[0-9]{7})/,a);match($3,/(AA[0-9]{7})/,b);print $1,a[1],",",b[1],$NF}' <<<"$a"
Text1 AA0123456,AA9876543 text1

Isso também funciona:

$ awk '{match($0,/(\w+\s)(\w+)(\w\w[0-9]{7})(\w+,\w+)(\w\w[0-9]{7})(\w+\s)(\w+)/,a);print a[1],a[3],",",a[5],a[7]}' <<<"$a"

UPDATE
Para seus novos requisitos e com o GNU awk você pode usar algo assim:

$ echo "$b"
Text1 somethingAA1111111something,elseAA2222222fooblahAA3333333^blahblahAA4444444 text1
Text2 somethingAA1111111something,elseAA7777777fooblahAA5454545^blah text2
Text3 somethingAA1111111something,elseAA2222222foo text3

$ awk '{gsub(/(AA[0-9]{7})/," & ",$2)}1' <<<"$b" |awk '{printf("%s ",$1);for (i=2;i<NF;i++) {if($i ~ /AA[0-9]+/) printf("%s%s",$i,(i==NF-1)?" ":",")}}{printf(" %s\n",$NF)}'
Text1 AA1111111,AA2222222,AA3333333,AA4444444  text1
Text2 AA1111111,AA7777777,AA5454545, text2
Text3 AA1111111,AA2222222, text3

Apenas a armadilha de que há uma vírgula extra em alguns registros após a última AAXXXXXXX. Espero que isso não seja um grande problema.

Esta solução combina dois awk. O primeiro awk transforma cada linha injetando um espaço antes e depois de cada AAXXXXXXX encontrado:

$ echo "$a"
Text2 somethingAA1234567something,elseAA0987654fooblahAA3333333^blah text2
$ awk '{gsub(/(AA[0-9]{7})/," & ",$2)}1' <<<"$a"
Text2 something AA1234567 something,else AA0987654 fooblah AA3333333 ^blah text2

Estes registros transformados são então alimentados para o segundo awk que imprime o primeiro campo, o último campo e os campos intermediários que correspondem ao padrão AAXXXXXXX

    
por 29.03.2017 / 23:18
2

Solução de bash para a solicitação atualizada:

echo "$b"
#Output
Text1 somethingAA1111111something,elseAA2222222fooblahAA3333333^blahblahAA4444444 text1
Text2 somethingAA1111111something,elseAA7777777fooblahAA5454545^blah text2
Text3 somethingAA1111111something,elseAA2222222foo text3

while IFS=" " read -r f1 f2 f3;do 
  g=($(grep -Po 'AA[0-9]{7}' <<<"$f2"));
  out=$(printf '%s,%s,%s\n' "$f1" "${g[*]}" "$f3");
  echo "$out" |sed 's/,/\x00/g; s/ /,/g; s/\x00/ /g';
done <<<"$b"
#Output
Text1 AA1111111,AA2222222,AA3333333,AA4444444 text1
Text2 AA1111111,AA7777777,AA5454545 text2
Text3 AA1111111,AA2222222 text3
    
por 30.03.2017 / 02:44
1

Perl

perl -pale '$_ = join $", $F[0], join(",", $F[1] =~ /AA\d{7}/g), @F[2..$#F]' yourfile

Bash

O uso de cat é intencional aqui, já que não queremos destruir os parâmetros posicionais ($1, $2, ..., $#) e, portanto, executar o while-loop em uma subcamada.

cat yourfile |
while read -r f1 f2 rem; do
   set -- "$f1" "$(printf '%s\n' "$f2" | grep -oP 'AA\d{7}' | paste -sd,)" "$rem"
   printf '%s\n' "$*"
done

Sed

sed -e '
   s/[^ ]*[ ]*/&\
\
/
   s/AA[0-9]\{7\}/\
&\
/g

   :loop
      s/\nAA[0-9]\{7\}\(\n\)/&/
      s/\n\n.*\(\n\n\)//
      s/\(\n\n\)\(AA[0-9]\{7\}\)\n/,/
   /\nAA[0-9]\{7\}\n/bloop

   s/,\n\n[^ ]*//
' yourfile
    
por 30.03.2017 / 10:54