Bash substituir string por comando

1

Eu tenho um comando (logcat) que gera um log longo como este:

07-27 09:26:22.416 17574 17886 D SurfaceControl: Excessive delay in setPowerMode()
07-27 09:26:22.421 17574 17599 I PowerManagerService: Sleeping (uid 1000)...
07-27 09:26:22.427 17489 17527 D audio_hw_primary: adev_set_parameters: enter: screen_state=off

O formato é: [Date] [Time] [Process ID] [Thread ID] [Log Type] [Text]

Em vez do id do processo, gostaria de ver o nome do processo (ou pacote para ser mais preciso).

O nome de um pacote pode ser recuperado pelo ID do processo usando:

echo "$PKG_PID_LIST" | grep -w $PID | cut -d ' ' -f1

Por exemplo:

$ echo "$PKG_PID_LIST" | grep -w 17489 | cut -d ' ' -f1
org.lineageos.audiofx

Se você está curioso, sim, estou no Android e estou criando a lista usando:

PKG_PID_LIST=$(eval $(pm list packages | cut -d ':' -f 2 | sed 's/^\(.*\)$/echo \"\$\(echo \) \$\(pidof \)\";/'))

No final, a saída deve ser algo como isto:

07-27 09:26:22.416 com.android.systemui 17886 D SurfaceControl: Excessive delay in setPowerMode()
07-27 09:26:22.421 com.android.systemui 17599 I PowerManagerService: Sleeping (uid 1000)...
07-27 09:26:22.427 org.lineageos.audiofx 17527 D audio_hw_primary: adev_set_parameters: enter: screen_state=off

edite: Exemplo de saída de $ PKG_PID_LIST:

$ echo "$PKG_PID_LIST"
com.android.deskclock 18937
com.android.systemui 17574
net.osmand.srtmPlugin.paid 
com.android.bluetoothmidiservice 
org.lineageos.audiofx 17489

(Pacotes que não estão rodando não possuem um PID. Existe sempre um espaço atrás do nome do pacote.)

    
por Forivin 27.07.2018 / 11:07

2 respostas

2

Ler de várias fontes de entrada e aplicar ações personalizadas exige a necessidade de awk . Você poderia simplesmente fazer isso como

awk 'FNR==NR{pidMap[$2]=$1; next}$3 in pidMap{$3=pidMap[$3]}1' <(echo "$PKG_PID_LIST") <(logcat)

O <() é uma sintaxe fornecida pelo shell bash que executa o comando dentro e faz a saída do comando como se estivesse aparecendo em um arquivo. Como o conteúdo do segundo arquivo, fazemos a saída de logcat aparecer lá. Então, awk tenta ler dois fluxos de entrada.

A lógica FNR==NR in awk usada quando lemos de mais de um fluxo de entrada de cada vez. FNR e NR são variáveis especiais que controlam os números de linha por arquivo e ao longo de todo o fluxo de entrada. Então, com a condição FNR==NR , basicamente definimos a ação após ela em {..} para ser executada no primeiro arquivo e a seguinte no segundo.

Assim, no primeiro fluxo arquivo , vemos a saída de PKG_PID_LIST a partir da qual criamos um hash-map com chave como o id do processo e o nome do processo como o valor . Quando terminarmos de processar esse arquivo, teríamos mapeado todos os PIDs com seus nomes.

No segundo arquivo, usamos esse mapa $3 in pidMap , o valor de $3 no segundo fluxo está presente como a chave que acabamos de processar, atualizamos o $3 no segundo fluxo ( $3 - coluna delimitada por terceiro espaço) como o valor mapeado para a chave. O {..}1 é uma ação em awk onde instruímos a reconstrução da linha com base nas modificações feitas (se nenhuma modificação for feita, imprimir linha como tal).

Se o logcat estiver produzindo saída continuamente e você quiser executar este comando depois que a saída for resolvida, sugiro gravar a saída em um arquivo temporário primeiro e depois passar esse arquivo como o arquivo 2º argumento em awk .

    
por 27.07.2018 / 11:33
0

Você pode fazer isso da seguinte maneira:

logcat |\
_PKG4PID_="$PKG_PID_LIST" \
perl -lpe '
    %h = reverse split /\s+/, $ENV{_PKG4PID_} if $. == 1;
    s/(?:\H+\h+){2}\K(\H+)/$h{$1}/;
' 

Explicação:

  • defina a variável de ambiente _PKG4PID_ igual à sua variável de shell PKG_PID_LIST .
  • Para que a primeira linha da entrada seja lida por perl , inicialize o hash %h com as chaves como os 2os campos e valores como 1 ° campos.
  • Agora, é apenas uma questão de localizar o terceiro campo na linha atual, /(?:\H+\h+){2}\K(\H+)/ , e substituí-lo pela entrada de hash correspondente, $h{$1} .
por 29.07.2018 / 07:32