Procura por um valor somente em uma coluna, usando awk, sed ou perl

0

Eu tenho um arquivo assim:

Marketing  Ranjit Singh   FULLEagles       Dean Johnson   
Marketing  Ken Whillans   FULLEagles       Karen Thompson 
Sales      Peter RobertsonPARTGolden TigersRich Gardener  
President  Sandeep Jain   CONTWimps        Ken Whillans   
Operations John Thompson  PARTHawks        Cher           
Operations Cher           CONTVegans       Karen Patel    
Sales      John Jacobs    FULLHawks        Davinder Singh 
Finance    Dean Johnson   FULLVegans       Sandeep Jain   
EngineeringKaren Thompson PARTVegans       John Thompson  
IT         Rich Gardener  FULLGolden TigersPeter Robertson
IT         Karen Patel    FULLWimps        Ranjit Singh   

Eu quero usar um comando grep para procurar por "John" na segunda coluna, procurando na última coluna, mas para cada "John" na segunda coluna, eu quero a saída da última coluna.

O resultado final deve ser assim:

       John Thompson                   Cher           
       John Jacobs                     Davinder Singh 
       Dean Johnson                    Sandeep Jain   
    
por BigDave 24.05.2014 / 01:47

4 respostas

4

#! /bin/bash
while read line; do
  if [[ ${line:11:15} =~ John ]]; then
    echo "      ${line:11:15}                   ${line:43}"
  fi
done <file
    
por 24.05.2014 / 02:20
3

Você pode realizar a seleção em grep combinando o número correto de caracteres do começo da linha:

grep -E '^.{11,22}John'

John tem que começar e terminar dentro do intervalo das colunas 11–26.

Substituir algumas colunas por espaço em branco não está dentro das capacidades do grep. Com o GNU grep, você pode usar -o para produzir apenas a parte correspondente, mas você não poderá combinar as duas colunas com espaço em branco adicional entre elas.

    
por 24.05.2014 / 02:58
2
tab=$(printf '\t')
cut -c12-26 file | paste - file | grep "^[^$tab]*John" | cut -c1-16,60-

Como Gilles disse que você não pode fazer isso com grep sozinho. grep significa g/re/p (um comando ed/ex/vi ), isto é, imprime as linhas que correspondem ao re.

    
por 24.05.2014 / 11:27
1

Vamos combinar algumas dicas das soluções que acabamos de mostrar.

De Stephane + Gilles:

grep -E '^.{11,22}John' source.txt  | cut -c12-26,44-
# or, if you want only "John " and not Johnson, add a space after John.
grep -E '^.{11,22}John ' source.txt  | cut -c12-26,44-

Aqui, você precisa usar /bin/grep e também /bin/cut .

De Gilles + Hauke:

grep -E '^.{11,22}John' source.txt | while read line; do echo "${line:11:14} ${line:43}"; done

Aqui, você precisa usar /bin/grep e também echo . No shell moderno, você encontra echo como um comando embutido , de modo que requer menos.

A solução da Hauke é a menos dispendiosa em termos de programas instalados: requer apenas echo (embutido em bash ), mas nem mesmo /bin/grep , como desejado na questão.

Atualizar Vamos jogar um pouco.
No dia a dia nós rodamos snippet de código, criado na hora e usado talvez nunca mais; nem sempre é conveniente gastar nosso tempo humano para otimizá-lo ou experimentar variações diferentes ... mas semel in anno licet insanire : Por outro lado, e com uma alta probabilidade, este foi um case-study question , talvez até mesmo um trabalho de casa não esteja completamente claro. Nesta óptica e IMHO, todas as diferentes abordagens e soluções são úteis.

Todos concordamos que, para um grande número de linhas, é melhor (mais rápido) usar um programa compilado então uma seqüência de comandos do shell. Mas o que é grande? Eu acho que números (e enredos) podem consertar idéias melhor do que apenas palavras: então vamos ver.

Aqui a receita : um conjunto de arquivos com um número crescente de linhas, N , estava preparado. Cada linha foi extraída aleatoriamente do original original publicado aqui.
Os valores de N usados são 11 22 55 110 220 550 1100 2200 5500 11000 110000 1100000 11000000 .

O snippet testado é:

  • O Cut+Paste+Grep+Cut tab=$(printf '\t') ; cut -c12-26 file | paste - file | grep "^[^$tab]*John" | cut -c1-16,60- - Verde
  • O Only Grep - Blue grep -E '^.{11,22}John' source.txt . Simplesmente o grep sem saída formatada conforme solicitado.
  • O Grep+Cut - vermelho [ grep -E '^.{11,22}John' source.txt | cut -c12-26,44- ].
  • O Grep+While - Violeta [veja acima nesta resposta, o grep antes e o loop while].
  • A While loop - Yellow uma solução bash completa que não exige grep

Para cada tamanho dos arquivos e snippet , um número de repetições, NRep , foi feito a partir de 400 (para os arquivos mais curtos) e diminuindo com N para 100, 10 e 1 para o último.
Foi registrado o valor de Tempo por linha , Tpl , também conhecido como tempo real , medido pelo em função time e média em NRep e N . Como os Tpl e N abrangem potências de 10, foi plotado o logaritmo comum (para base 10, ou os poderes de 10). As linhas relatadas são curvas de Bézier que tocam cada ponto.

ParagrandesvaloresdeN,oTempoporLinhasetornaquaseconstante.Éochamadocomportamentoassintótico.Comoesperado,quantomenoronúmerocompiladodoprogramausado,maisrápidoseráoresultado.

Pelo contrário, com arquivos pequenos, o resultado é o oposto. As eficiências de diferentes códigos se cruzam em uma região que (para o nosso exemplo) está entre 40 e 140 linhas. Mesmo que seja verdade que, para arquivos pequenos, é pequeno mesmo o tempo humano usado, a mesma consideração não é mais válida quando é necessário trabalhar com um grande número de pequenos arquivos: o código bash puro (amarelo) que assintoticamente é 8,12 vezes mais lento que o verde, e até 157 vezes mais lento que o vermelho (para o arquivo de linhas 11M ele usa 334,56 s. em vez de 41,21s do verde e 2,16 do vermelho) Em vez disso, é respectivamente 2,16 e 1,58 vezes mais rápida para as 11 linhas, quando usa 1,20s para 400 repetições em vez de 1,89s do vermelho ou 2,59s do verde.

Conclusão: Quanto mais você souber, melhor você desafiar e verificar sempre que puder! : -)

Ps > Uma consideração semelhante pode ser feita no tempo do usuário e tempo do sistema , mas com uma região de cruzamento ligeiramente diferente.

bash 4.3.11 (1) -release em pasta (GNU coreutils) 8.21 em corte (GNU coreutils) 8.21
grep (GNU grep) 2.16
kernel 3.13.0-24-generico x86_64

    
por 24.05.2014 / 20:34