combinando e mesclando linhas com o awk e imprimindo com o Solaris

2

Eu quero mesclar o padrão de correspondência com awk em um sistema Solaris.

$ luxadm probe 
 No Network Array enclosures found in /dev/es

 Found Fibre Channel device(s): 
 Node WWN:2000000c50f1c8da Device Type:Disk device 
 Logical Path:/dev/rdsk/c1t1d0s2 
 Node WWN:2000000c50f1d9c9 Device Type:Disk device 
 Logical Path:/dev/rdsk/c1t0d0s2

Observação - Enquanto eu estou tentando com o awk , é preciso apenas uma linha sendo mesclada do último.

$ luxadm probe |awk '/Node/{n=$2}/Logical/{l=$2} END {print n,l}' 
 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2

Enquanto a saída esperada é:

WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2
WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2 
    
por krock1516 11.04.2015 / 12:15

4 respostas

3

A resposta curta que ainda não foi mencionada em awk

awk '/Node/{n=$2; getline; print n " "$2; next}' filename
  • /Node/ # Procure o nó padrão e armazene o segundo campo em n variable n=$2
  • getline # Mover para a próxima linha (Aqui é onde Logical linha começa), imprima o que está armazenado na variável n e depois o segundo campo da próxima linha.
  • next # Parar de processar o registro atual e passar para o próximo.
por 11.04.2015 / 12:50
3

O motivo pelo qual o faililng é porque você está imprimindo apenas as variáveis capturadas uma vez, em um bloco END{} . Isso significa que apenas os dois últimos serão impressos. A @Costas já deu a você uma abordagem mais elegante, mas você também pode usar a mesma lógica que estava tentando com uma pequena alteração:

awk '{ if(/Node/){
        if(length(n)){print n,l} ## if we have an n, print them
        n=$2
        }
        if(/Logical/){l=$2}
      } 
        END {print n,l}' 

Como alternativa, você pode usar outras ferramentas:

  1. GNU grep / perl

    luxadm probe |  grep -Po '^\s*(Node|Logical)\s*\K.*?(\s|$)' file | 
        perl -lne '$. % 2 ? printf : print'
    
  2. Perl

    luxadm probe |  
      perl -ne 'chomp;if(s/.*(WWN:.*?)\s.*/$1 / || s/.*(Path:.*?)$/$1\n/){print}'
    
por 11.04.2015 / 12:43
2

Você deve usar sed , na minha opinião. Em primeiro lugar, ele geralmente supera o awk e, nesse caso, oferece uma solução mais simples:

sed -n 'N;s/Node \([^ ]*\).*Logical//p' <infile

... que, dados seus dados de exemplo, imprime ...

 WWN:2000000c50f1c8da Path:/dev/rdsk/c1t1d0s2
 WWN:2000000c50f1d9c9 Path:/dev/rdsk/c1t0d0s2

Para cada linha lida, sed também obtém o N ext anexado ao espaço padrão após um delimitador de \n ewline inserido. Portanto, o s/// ubstitution acima abrange duas linhas e imprime os dois campos que você deseja separar apenas por um espaço e somente quando uma correspondência for encontrada.

A sintaxe sed acima deve ser totalmente portável para qualquer sistema POSIX.

    
por 11.04.2015 / 13:33
1

Se você quiser awk

awk -v RS=' Node ' -v FS=' Logical Path:| ' '/WWN/{print $1,$6}'

Outro (pode ser simples)

awk -F":| " '/Node/{printf "%s ", $3":"$4}/Logical Path/{print $4}'

com restante Path:

awk '/Node/{printf "%s ", $2}/Logical Path/{print $2}'

ou

awk '/Node/{wwn=$2}/Logical Path/{print wwn,$2}'

E o GNU sed finalmente:

sed -n '/WWN/{s/^\s*\S* *\|\( \S*\)\{3\}\s*$//g;N;s/\n\s*\S*//;p}'
    
por 11.04.2015 / 12:33