Para qual fluxo o xsel imprime o aviso sem nova linha?

5

xsel é um programa com o qual você pode acessar a área de transferência do sistema a partir da linha de comando. Se não houver uma nova linha no final do conteúdo copiado, ele imprimirá um aviso após o conteúdo da área de transferência da seguinte forma:

$ xsel -b
copied text
\ No newline at end of selection

Anteriormente eu costumava pensar que esse aviso é impresso no erro padrão, mas hoje descobri que o aviso não está lá, mesmo se o erro padrão for mesclado com a saída padrão. xsel-b |& less apenas imprime o texto copiado, sem O aviso. Por que se comporta assim?

    
por saga 13.01.2017 / 16:16

2 respostas

2

Observe que esse é o comportamento de xsel nas versões ainda não lançadas de xsel . Introduzido por esta mudança em 2008.

É comum que as seleções X contenham texto que não termine em caracteres de nova linha. Se você despejar como está, isso resulta em uma linha não terminada sendo exibida. Com shells antigos como bash , o display se torna:

bash-4.4$ xsel -b
xselbash-4.4$

(aqui com a seleção CLIPBOARD contendo xsel ). O próximo prompt acaba sendo anexado ao conteúdo da seleção.

Os shells modernos, como zsh ou fish , estão detectando quando a saída do último comando não termina em nova linha e fornece uma indicação visual.

com zsh :

prompt% xsel -p
xsel%
prompt%

(o vídeo reverso % após xsel sendo a indicação de que uma nova linha estava faltando).

com fish :

prompt ~> xsel -p
x⏎
prompt ~>

Aqueles mais recentes xsel fornecem essa indicação visual:

bash-4.4$ xsel -b
xsel
\ No newline at end of selection
bash-4.4$

Agora, isso só é útil se o xsel for executado no prompt de um shell interativo antigo.

Em particular, essa indicação "Não há nova linha" não seria desejável quando usada como:

selection=$(xsel -b)

(onde stdout de xsel é um pipe) ou:

xsel -b > selection.txt

(onde o stdout de xsel é um arquivo normal).

É por isso que xsel só exibe essa indicação somente quando o stdout vai para um dispositivo tty.

Agora, onde é exibido? Bem, a intenção é exibi-lo nesse dispositivo tty. Se você correr sob strace, você verá:

$ strace -e write ./xsel -b
write(1, "xsel", 4xsel)                     = 4
write(2, "\n\ No newline at end of selectio"..., 34
\ No newline at end of selection
) = 34
+++ exited with 0 +++

O que confirma a origem : é exibido no stderr. Terminar quando stdout não é um terminal:

$ strace -e write ./xsel -b  > /dev/null
write(1, "$ strace -e write ./xsel -b | ca"..., 104) = 104
+++ exited with 0 +++

Não é saída de todo. Agora pode-se argumentar que é um pouco bobo produzir no stderr quando a intenção é produzir essa notificação para o terminal (o stderr pode ser redirecionado para um arquivo de log por exemplo como em xsel -b 2> logfile ), mas:

  • Geralmente, quando stdout é um dispositivo terminal, o stderr também é.
  • Isso significa que você pode desativar essa notificação quando executado em um terminal com xsel -b 2> /dev/null , o que seria mais eficiente do que xsel -b | cat .
  • O isatty() retornaria verdadeiro para um dispositivo serial que não está conectado a um terminal.
por 14.01.2017 / 12:39
2

É simples o suficiente para testar com:

xsel -b > xsel.out 2> xsel.err

A mensagem estará em um dos dois arquivos. Se estiver em xsel.out , a mensagem será enviada pela saída padrão; se estiver no outro arquivo, então é através do erro padrão; se estiver em algo mais estranho, então algo muito estranho está acontecendo, e você precisa ter uma longa e séria conversa com seu kernel.

    
por 13.01.2017 / 17:25