De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.


Redirecionamentos - Parte 6 - Recebendo/mandando dados para clipboard

Colaboração: Julio Cezar Neves

Data de Publicação: 06 de outubro de 2019

Antes da dica de hoje, um recadinho rápido. Amanhã se encerram as inscrições para a última turma do ano do curso Programação Shell Linux, com o Professor Julio Neves.

»»» Clique aqui ««« para saber mais e ver os depoimentos de nossos ex-alunos.


Escrevi clipboard só para ficar fácil de entender o título, porque efetivamente o Shell manipula 3 áreas de transferências:

Nome da área Como mandar para área Como baixar da área
XA_PRIMARY Arrastando o mouse Botão do meio
XA_CLIPBOARD <CTRL>+C <CTRL>+V
XA_SECONDARY Por programa Por programa

Eu conheço duas ferramentas para trabalhar com esses buffers: o xsel e o xclip. Nesse artigo abordaremos somente o xclip por ser o mais difundido.

O xclip tem inúmeras opções, mas mostrarei somente as mais usadas. São elas:

Opção Ação
-i O xclip receberá dados da entrada primária ou arquivo(s)
-o O xclip enviará dados para a saída
-selection Seleciona buffers. Opções: primary; secondary ou clipboard[1]
-f Não filtra a saída. Joga-a na tela
-t Seleciona tipo de alvo que será copiado

[1] Para definir a seleção basta usar o primeiro caractere de cada um dos buffers. Assim, basta usar p, s ou c, respectivamente. Você também pode abreviar -selection escrevendo somente -sel.

Bem, basicamente já vimos toda a teoria, vamos aos exemplos para entendê-la.

Transferindo o conteúdo de arquivo para o buffer primário:

$ xclip -i -selection p arquivo

Mas como a opção -i é padrão e primary (p) é o padrão da opção -selection, esse exemplo poderia ser escrito assim:

$ xclip ARQUIVO

Pronto! O conteúdo de arquivo já está armazenado no buffer primário. Você verá em diversos lugares (diria até que na maioria dos lugares) isso sendo feito dessa maneira:

$ cat ARQUIVO | xclip   # ARGHHH!

Isso é uma perda de tempo e é uma forma de escrever mal o Shell (chama-se cat command abuse).

Agora que você já copiou o arquivo, estando no terminal você pode devolvê-lo de duas formas:

  1. Clicando no botão do meio ou no da esquerda e da direita simultaneamente;
  2. Executando o comando:

    $ xclip -o

Onde o conteúdo do buffer será passado para a saída primária (opção -o).

A diferença das duas formas é que, na primeira, os dados são interpretados e na segunda não. Caso ARQUIVO fosse um script, da primeira forma ele seria executado, quando fosse colado em um terminal da segunda seria somente listado.

Você pode redirecionar a saída do xclip para um comando, de forma a selecionar o texto que você deseja.

Para mostrar isso, suponha que eu tenha visto um grande script na Internet do qual eu queria testar só uma rotina de poucas linhas de código. 99% das pessoas colariam o script inteiro em um arquivo e o editariam colocando um hashtag (#) antes de cada uma das 100 linhas desnecessárias de forma a transformá-las em um comentário.

Podemos fazer isso com muito menos trabalho, mas vou usar a saída do comando seq 5 para fingir que é o script enorme e vou fazer xclip -sel c para fingir que fiz um <CTRL>+C no script. Então vamos salvar o "script":

$ seq 5 | xclip -sel c

O efeito dessa linha - na qual omiti a opção -i por ser a default - é o mesmo que se eu tivesse arrastado o mouse por cima dos 5 números da saída do seq e tivesse feito um <CTRL>+C.

Agora vamos meter o hashtag no início das linhas de 2 até 4:

$ xclip -o -sel c | sed '2,4 s/^/# /'
1
# 2
# 3
# 4
5

Como os dados do xclip podem vir via pipe ou via nome do arquivo a ser copiado, para não ter trabalho, desenvolvi uma função que coleta os dados da entrada primária ou de um arquivo e os coloco no clipboard. Todo programador deve ter um arquivo no qual ele tenha as funções que mais usa. Essa função é assim:

function LeEntrada
{
if ! [[ -t 0 ]]  #  Testa se file descriptor 0 (entrada
                 #+ primária) está aberto no terminal
then
    echo -n "$(< /dev/stdin)" |
        xclip -selection c && \
            echo "Copiado para clipboard"
else
    if [[ -z "$@" ]]  # Cadê o(s) parâmetro(s)
    then
        echo "Uso:
        $0 ARQ - Manda arquivo ARQ p/ clipboard
        CMD | $0 - Manda saída de CMD p/ clipboard" >&2
        return 1
    fi
    # Então parâmetro passado foi um arquivo.
    if [[ ! -f "$@" ]]
    then
        echo  Arquivo $@ não existe
        return 1
    else
        xclip -i -selection clipboard "$@"
        echo "Arquivo "$@" copiado para clipboard"
    fi
fi
}

Digamos que você queira mandar uma saída simultaneamente para o buffer primário e para a área de transferência (clipboard). Se você fizer:

$ echo "Olá" | xclip -i -sel c | xclip -i -sel p

Isso não funcionará porque o primeiro xclip não gerará saída alguma para o segundo. Nesse caso é necessário usar a opção -f, que mandará o conteúdo do buffer para a saída. Veja:

$ echo "Olá" | xclip -i -sel c
$ echo "Olá" | xclip -i -sel c -f
Olá

Então, para mandar para ambos os buffers, o correto seria:

$ echo "Olá" | xclip -i -sel c -f | xclip -i -sel p

Para encerrarmos esse assunto, só mais um exemplinho bobo (como quase todos, dos poucos que existem no man):

$ xclip -t text/html index.html

Onde a opção -t especifica que o alvo será um arquivo de html.

Só para não dizer que não falei sobre o buffer secundário, veja esse exemplo, onde uso as três áreas de transferências:

$ echo Primario   | xclip -sel p
$ echo Secundário | xclip -sel s
$ echo Clipboard  | xclip -sel c
$ xclip -o -sel p
Primario
$ xclip -o -sel s
Secundário
$ xclip -o -sel c
Clipboard
Error: No site found with the domain 's2.dicas-l.com.br' (Learn more)