Como extrair certos dados de uma linha

7

Problema

Eu estava procurando uma solução no Bash que pudesse extrair informações específicas após uma string especificada.

Exemplo

Por exemplo (da execução de acpi ):

Battery 0: Discharging, 37%, 01:33:20 remaining

Como posso extrair a porcentagem após a alta? Nesse caso, seria 37% ...

Notas

Estou procurando uma solução simples que não exija muitos argumentos de comando.

    
por NerdOfCode 04.01.2018 / 18:09

5 respostas

9

Não sei ao certo o que você quer dizer com "uma solução no bash", mas awk pode fazer o trabalho:

awk -F", " '{print}'
  • -F", " - escolha vírgula seguida de espaço como o delimitador F ield, isso divide sua linha de exemplo em três colunas, onde a segunda é 37%
  • '{print}' - imprime a segunda coluna

Ou que tal sed ?

sed -E 's/.* ([0-9]+%).*//'
    
por dessert 04.01.2018 / 18:13
12

Aqui estão alguns:

$ acpi | grep -oP '\d+%'
99%
$ acpi | awk -F',' '{print }'
 99%
$ acpi | perl -pe 's/.*?(\d+%).*//'
99%
    
por terdon 04.01.2018 / 18:13
7
  

Eu estava procurando uma solução no bash que possa extrair informações específicas após uma string especificada.

Depois de uma string especificada? Nenhuma das duas respostas postadas anteriormente faz especificamente isso (porque pegar texto depois de uma string não é a melhor maneira de obter as informações que você disse que queria no seu exemplo).

Aqui estão algumas maneiras de obter texto depois de uma string. Eu usei o seu exemplo, embora a resposta da sobremesa e a resposta de terdon ambos demonstram abordagens mais apropriadas para este caso particular.

Use \K do Perl, por exemplo, em grep com -P (permitir regex Perl) e -o (somente correspondência):

grep -Po 'string\Kdesired'

Em que string é uma expressão que corresponde ao que vem antes do que você deseja e desired é uma expressão que corresponde ao que você deseja gerar. Isso é útil quando o padrão desejado ocorre em outro lugar no arquivo / linha (por exemplo, é um número e o arquivo / linha contém outros números). No seu exemplo, isso poderia ser algo como:

$ acpi | grep -Po 'ing, \K[^,]+'
79%

[^,]+ significa alguns caracteres que não são uma vírgula, portanto, isso pode capturar texto até uma vírgula. Também poderíamos usar ... para obter três caracteres, mas como apontado em um comentário por PerlDuck , é possível que o padrão que você quer aqui seja maior ou menor que 3 caracteres.

Em sed , você pode usar grupos de captura com ( e ) :

sed -r 's/.*string(desired).*//' 

em que é o que foi salvo com ( ) . Por exemplo:

$ acpi | sed -r 's/.*ing, ([^,]+).*//'
89%

Aqui está uma maneira de fazer isso apenas com o Bash no seu exemplo

$ output=$(acpi); string="${output#*ing, *}"; desired="${string%,*}"; echo "$desired"
96%

${var#string*} apara var antes de string (inclusive) e ${var%string*} apara var após string (inclusive).

Esta não é de forma alguma uma lista exaustiva. Existem muitas maneiras de fazer isso:)

    
por Zanna 04.01.2018 / 20:23
6

Uma solução bash, conforme solicitado, sem estranhos awkisms ou sedismas sedosos:

my_battery=( $(acpi) ); echo ${my_battery[3]}

Isso usa a substituição de comandos, cria uma matriz da saída do comando e exibe o 4º elemento da matriz.

Isso funciona com a saída do acpi, que aparentemente sempre tem a porcentagem da bateria como o quarto parâmetro. Se você quiser encontrar o elemento da matriz após "Discharging", você não obterá um resultado se o acpi informar "Battery 0: Full, 100%".

    
por Wastrel 05.01.2018 / 17:31
3

Você também pode usar extração de substring com

input=$(acpi)
expr "${input#*,[[:space:]]}" : '\([^,]*\)'
    
por Bertrand Martel 05.01.2018 / 00:13