Extrair partes únicas de texto do arquivo com awk, sed ou grep

4

Da saída de pactl list sink-inputs , eu preciso pegar o número sink input para o VLC. Antes disso, estou tentando extrair a peça que contém a saída apenas para o VLC. Todos os métodos que pensei que funcionariam têm deficiências. Este é um exemplo de saída:

$ pactl list sink-inputs
Sink Input #1373
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10350
    Sink: 0
    Sample Specification: float32le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"float32le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0: 100% 1: 100%
            0: 0,00 dB 1: 0,00 dB
            balance 0,00
    Buffer Latency: 453287 usec
    Sink Latency: 19697 usec
    Resample method: copy
    Properties:
        media.role = "video"
        media.name = "audio stream"
        application.name = "VLC media player (LibVLC 2.1.5)"
        native-protocol.peer = "UNIX socket client"
        native-protocol.version = "28"
        application.id = "org.VideoLAN.VLC"
        application.version = "2.1.5"
        application.icon_name = "vlc"
        application.language = "pt_BR.UTF-8"
        application.process.id = "19965"
        application.process.machine_id = "948146522454ae6aa2bb8ed153f4bce4"
        application.process.session_id = "948146522454ae6aa2bb8ed153f4bce4-1431635199.85146-1790309877"
        application.process.user = "teresaejunior"
        application.process.host = "localhost"
        application.process.binary = "vlc"
        window.x11.display = ":0.0"
        module-stream-restore.id = "sink-input-by-media-role:video"

Sink Input #1378
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10378
    Sink: 0
    Sample Specification: s16le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"s16le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0:  87% 1:  87%
            0: -3,63 dB 1: -3,63 dB
            balance 0,00
    Buffer Latency: 989841 usec
    Sink Latency: 19572 usec
    Resample method: n/a
    Properties:
        media.name = "audio stream"
        application.name = "mplayer2"
        native-protocol.peer = "UNIX socket client"
        native-protocol.version = "28"
        application.process.id = "20093"
        application.process.user = "teresaejunior"
        application.process.host = "localhost"
        application.process.binary = "mplayer2"
        application.language = "C"
        window.x11.display = ":0.0"
        application.process.machine_id = "948146522454ae6aa2bb8ed153f4bce4"
        module-stream-restore.id = "sink-input-by-application-name:mplayer2"

Tanto awk '/^Sink/,/VLC/' como sed -n '/^Sink/,/VLC/p' pegam a parte VLC, mas depois também pegam a parte mplayer2 e vão até o final da saída:

$ pactl list sink-inputs | awk '/^Sink/,/VLC/'
Sink Input #1373
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10350
    Sink: 0
    Sample Specification: float32le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"float32le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0: 100% 1: 100%
            0: 0,00 dB 1: 0,00 dB
            balance 0,00
    Buffer Latency: 437414 usec
    Sink Latency: 19666 usec
    Resample method: copy
    Properties:
        media.role = "video"
        media.name = "audio stream"
        application.name = "VLC media player (LibVLC 2.1.5)"
Sink Input #1379
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10381
    Sink: 0
    Sample Specification: s16le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"s16le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0:  87% 1:  87%
            0: -3,63 dB 1: -3,63 dB
            balance 0,00
    Buffer Latency: 980045 usec
    Sink Latency: 19563 usec
    Resample method: n/a
    Properties:
        media.name = "audio stream"
        application.name = "mplayer2"
        native-protocol.peer = "UNIX socket client"
        native-protocol.version = "28"
        application.process.id = "20093"
        application.process.user = "teresaejunior"
        application.process.host = "localhost"
        application.process.binary = "mplayer2"
        application.language = "C"
        window.x11.display = ":0.0"
        application.process.machine_id = "948146522454ae6aa2bb8ed153f4bce4"
        module-stream-restore.id = "sink-input-by-application-name:mplayer2"

grep -Poz '^Sink(?s).*?VLC' funciona, mas se a saída do VLC vier depois do mplayer2, ele falhará (um teste com o mplayer2 em vez do VLC):

$ pactl list sink-inputs | grep -Poz '^Sink(?s).*?mplayer'
Sink Input #1373
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10350
    Sink: 0
    Sample Specification: float32le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"float32le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0: 100% 1: 100%
            0: 0,00 dB 1: 0,00 dB
            balance 0,00
    Buffer Latency: 441088 usec
    Sink Latency: 18159 usec
    Resample method: copy
    Properties:
        media.role = "video"
        media.name = "audio stream"
        application.name = "VLC media player (LibVLC 2.1.5)"
        native-protocol.peer = "UNIX socket client"
        native-protocol.version = "28"
        application.id = "org.VideoLAN.VLC"
        application.version = "2.1.5"
        application.icon_name = "vlc"
        application.language = "pt_BR.UTF-8"
        application.process.id = "19965"
        application.process.machine_id = "948146522454ae6aa2bb8ed153f4bce4"
        application.process.session_id = "948146522454ae6aa2bb8ed153f4bce4-1431635199.85146-1790309877"
        application.process.user = "teresaejunior"
        application.process.host = "localhost"
        application.process.binary = "vlc"
        window.x11.display = ":0.0"
        module-stream-restore.id = "sink-input-by-media-role:video"

Sink Input #1380
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10396
    Sink: 0
    Sample Specification: s16le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"s16le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0:  87% 1:  87%
            0: -3,63 dB 1: -3,63 dB
            balance 0,00
    Buffer Latency: 989841 usec
    Sink Latency: 18084 usec
    Resample method: n/a
    Properties:
        media.name = "audio stream"
        application.name = "mplayer

A saída desejada:

Sink Input #1373
    Driver: protocol-native.c
    Owner Module: 9
    Client: 10350
    Sink: 0
    Sample Specification: float32le 2ch 44100Hz
    Channel Map: front-left,front-right
    Format: pcm, format.sample_format = "\"float32le\""  format.rate = "44100"  format.channels = "2"  format.channel_map = "\"front-left,front-right\""
    Corked: no
    Mute: no
    Volume: 0: 100% 1: 100%
            0: 0,00 dB 1: 0,00 dB
            balance 0,00
    Buffer Latency: 441088 usec
    Sink Latency: 18159 usec
    Resample method: copy
    Properties:
        media.role = "video"
        media.name = "audio stream"
        application.name = "VLC media player (LibVLC 2.1.5)"
    
por Teresa e Junior 19.05.2015 / 19:53

3 respostas

7

com ed :

ed -s <<'IN'
r !pactl list sink-inputs
/VLC/+,$d
?Sink Input?,.p
q
IN

Ele r leva a saída do comando para o buffer de texto, d elimina tudo após a primeira linha corresponder a VLC e, em seguida, p rints da linha anterior correspondendo Sink Input à linha atual.

com sed :

pactl list sink-inputs | sed -n 'H;/Sink Input/h;/VLC/{x;p;q}'

Acrescenta cada linha a H old buffer, se uma linha corresponder a Sink Input substitui o buffer h old e quando uma linha corresponde ao VLC, ele x altera o espaço de retenção w. espaço padrão, p rints e q uits.

    
por 19.05.2015 / 20:21
6

Eu usaria o modo de parágrafo do Perl:

pactl list sink-inputs | perl -00ne 'print if s/(.*?VLC.*?\n).*/$1/ms' 

O -00 define o separador de registro de entrada como \n\n , portanto, uma "linha" é um parágrafo. Em seguida, a substituição corresponderá a todos até o primeiro VLC e, em seguida, até a primeira nova linha, e os salvará como $1 . Tudo depois disso é removido (já que estamos substituindo tudo por $1 ). Finalmente, "linhas" onde essa substituição foi bem sucedida são impressas.

    
por 19.05.2015 / 20:16
3

Estes são efetivamente registros de várias linhas separados por uma linha em branco. O Awk é ótimo para lidar com esse tipo de dados:

pactl list sink-inputs | awk -v RS="" '/VLC/' 

Se você quer ser realmente exigente em não incluir a parte inferior do registro após a primeira ocorrência de "VLC", então:

pactl list sink-inputs | awk -v RS="" -v FS="\n" '/VLC/{ for(i=1; i<=NF; i++) { print $i; if($i ~ /VLC/) exit}}' 
    
por 20.05.2015 / 08:31