Retorna a linha anterior de todos os jogos

4

Eu preciso pegar a saída de várias linhas de um programa, combinar uma string e retornar a linha anterior de todas as correspondências.

Um exemplo da saída do programa:

$ jack_lsp -p
firewire_pcm:analog-1_out
        properties: input,physical,terminal,
firewire_pcm:analog-2_out
        properties: input,physical,terminal,
firewire_pcm:analog-1_in
        properties: output,physical,terminal,
firewire_pcm:analog-2_in
        properties: output,physical,terminal,
$

Eu preciso corresponder, por exemplo, 'entrada' e retornar a linha anterior de todas as correspondências. Então, no exemplo, a saída esperada seria:

firewire_pcm:analog-1_out
firewire_pcm:analog-2_out

Aqui está o que eu tenho, mas só retorna a primeira correspondência:

$ jack_lsp -p | grep -B1 input | head -1
firewire_pcm:analog-1_out
$

O que estou fazendo de errado?

    
por Christopher Brown 13.11.2017 / 19:23

4 respostas

6

Este é o comando que você está tentando:

jack_lsp -p | grep -B1 input | head -1

O problema com isso é que head -1 retornará a primeira linha do fluxo inteiro dos dados que são canalizados para ele.

Tente este comando awk :

jack_lsp -p | awk '/input/{print previous_line}{previous_line=$0}'

Ele imprimirá a linha antes de cada linha que contiver a string "input". Aqui está o resultado para seus dados de exemplo:

user@host:~$ cat <<HEREDOC | awk '/input/{print previous_line}{previous_line=$0}'
firewire_pcm:analog-1_out
        properties: input,physical,terminal,
firewire_pcm:analog-2_out
        properties: input,physical,terminal,
firewire_pcm:analog-1_in
        properties: output,physical,terminal,
firewire_pcm:analog-2_in
        properties: output,physical,terminal,
HEREDOC

firewire_pcm:analog-1_out
firewire_pcm:analog-2_out

Para obter mais informações sobre essa abordagem awk , consulte a postagem a seguir:

Você pode realizar o mesmo usando sed :

<!-- language: bash -->

jack_lsp -p |sed -n '/input/{x;p;d;}; x'

Para obter mais informações sobre essa abordagem sed , consulte a postagem a seguir:

No seu caso particular, parece que a string com a qual você está combinando (isto é, "entrada") não ocorre na linha anterior, então você pode filtrar essas linhas usando grep também, ou seja:

jack_lsp -p | grep -B1 'input' | grep -v 'input

Você também pode obter o mesmo resultado que a abordagem awk acima, complementando grep com alguns scripts de shell, embora o resultado não seja tão compacto:

jack_lsp -p | (
    unset previous_line;
    while read line; do
        if grep -q input <<< "${line}" && [[ -n "${previous_line}" ]]; then
            echo "${previous_line}";
        fi;
        previous_line="${line}";
    done
)
    
por 13.11.2017 / 19:34
4

Usando o gnu-grep (disponível para todas as plataformas e instalado por padrão na maioria) nós podemos:

jack_lsp -p | grep -zPo '.*\n(?=.*input)'

onde

  • -z significa "linhas" separadas por nulo (na verdade, ele acaba sugando o arquivo completo) - para ter padrões de múltiplas linhas
  • -P expressão regular semelhante a perl dialect - para ter lookaheads
  • '.*\n(?=.*input)' uma linha vista por outra linha contendo "entrada"
por 13.11.2017 / 20:04
3

Por que não apenas simplificar e usar ex , que tem endereçamento reverso:

printf '%s\n' 'g/input/-p' | ex file.txt

Para executá-lo em um pipeline, em vez de em um arquivo, ele parece um pouco mais complicado, mas funciona da mesma maneira:

jack_lsp -p | ex -s /dev/stdin -c $'g/input/-p\nq'
    
por 14.11.2017 / 03:39
0

Este snippet:

# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
pl " Input data file $FILE:"
head $FILE

pl " Expected output:"
cat $E

pl " Results:"
rm -f f1
ed --silent $FILE > f1 <<EOF
g/input/.-1p
q
EOF
head f1

produz:

-----
 Input data file data1:
firewire_pcm:analog-1_out
        properties: input,physical,terminal,
firewire_pcm:analog-2_out
        properties: input,physical,terminal,
firewire_pcm:analog-1_in
        properties: output,physical,terminal,
firewire_pcm:analog-2_in
        properties: output,physical,terminal,

-----
 Expected output:
firewire_pcm:analog-1_out
firewire_pcm:analog-2_out

-----
 Results:
firewire_pcm:analog-1_out
firewire_pcm:analog-2_out

O comando ed é simplesmente: 1) encontre uma linha que corresponda a "entrada" 2) imprima a linha anterior.

Executar em um sistema como:

OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution        : Debian 8.9 (jessie) 
ed GNU Ed 1.10

Felicidades ... felicidades, drl

    
por 14.11.2017 / 03:16