Extrai dois valores da saída de um comando

2

Estou usando o seguinte comando em um script para obter informações sobre o wi-fi sintético:

echo "$(
    iw dev wlp1s0 link |
    grep '^\s*SSID:\s' |
    sed -r 's/^\s*SSID:\s//'
) $(
    iw dev wlp1s0 link |
    grep '^\s*signal:\s' |
    sed -r 's/^\s*signal:\s//'
)"

Funciona e a saída é como:

MySSID -46 dBm

No entanto, parece estúpido fazer a mesma chamada para iw dev wlp1s0 link duas vezes, quando sei que o resultado será o mesmo. Além disso, gostaria de evitar armazenar a saída de iw em uma variável temporária.

Existe algo que eu possa fazer, talvez usando tee , para "duplicar" a saída de iw para duas tarefas e concatenar os resultados?

    
por fonini 23.05.2015 / 08:12

3 respostas

1

Não há nada errado em usar uma variável temporária: variáveis são feitas para armazenar dados a serem usados várias vezes.

Neste caso, você pode combinar as duas chamadas grep / sed em uma única chamada para o GNU grep, sed ou awk. É fácil com o sed: passar a opção -n para produzir somente linhas explicitamente impressas e imprimir as linhas nas quais uma substituição é feita.

echo "$(
    iw dev wlp1s0 link |
    sed -nr -e 's/^\s*SSID:\s//p' -e 's/^\s*signal:\s//'
)"

Existe uma diferença em relação ao seu script original: o SSID e os valores do sinal são impressos na ordem em que aparecem na saída de iw . Se você quisesse ser independente dessa ordem, seria complicado com sed, então o awk seria a ferramenta preferida. Com essa abordagem, é tão fácil obter a saída em uma única linha. O script a seguir imprime o último valor para cada configuração ( iw gera apenas um, portanto, neste caso específico, não importa); mudar, e. ssid = $0 to ssid = ssid " " $0 para imprimir todos eles.

iw dev wlp1s0 link | awk '
    $1=="SSID:" {sub(/[^:]*:[[:space:]]*/,""); ssid = $0}
    $1=="signal:" {sub(/[^:]*:[[:space:]]*/,""); signal = $0}
    END {print ssid, signal}
'

Em geral, se você quiser enviar a saída de um comando para dois filtros diferentes, você pode usar tee e passá-lo a substituição de processos . Este é um recurso bash (do ksh93, também presente no zsh, mas não no sh simples) que generaliza os pipes. O comando tee vê um nome de arquivo que designa um canal conectado ao comando especificado.

iw dev wlp1s0 link | tee >(
    grep '^\s*SSID:\s' |
    sed -r 's/^\s*SSID:\s//'
  ) |
    grep '^\s*signal:\s' |
    sed -r 's/^\s*signal:\s//'

Uma limitação dessa abordagem é que o comando na substituição do processo é executado em sua própria sub-camada. Você não pode obter variáveis de volta ou controlar como sua saída é intercalada com outras.

    
por 25.05.2015 / 01:42
1

Aqui está um forro do comando iw que tem a mesma saída que você.

iw dev wlp1s0 link | grep 'SSID:\|signal' | awk '{printf "%s ", $2$3}'

Minha saída:

ZyXEL-AP-2,4GHz -46dBm
    
por 23.05.2015 / 09:45
0

Algo assim?

iw dev wlp1s0 link |
grep -E '^\s*(SSID|signal):\s' |
sed -r 's/^\s*(SSID|signal):\s//' |
awk '{printf $0}'

grep aceitará (SSID|signal): , portanto corresponderá a SSID: e signal: .

-E é opcional, mas se você não usá-lo, pense em escapar de um caractere de significado especial. Aqui, seria \(SSID\|signal\):

O mesmo regex pode ser usado para a parte sed .

Finalmente, use awk para remover todas as novas linhas finais (caso contrário, a saída será exibida em 2 linhas).

    
por 23.05.2015 / 09:45