Como posso enviar comandos para qualquer terminal?

4

Costumo usar mais de um terminal (ou emulador de terminal) por vez; e enquanto em X eu posso copiar e colar comandos, além de não ser muito prático, obviamente não funciona no verdadeiro TTY. A primeira ideia que me ocorre é algo parecido:

command > /dev/sometty

Infelizmente, o command é executado antes de ser canalizado e nenhum truque como echo 'command' funcionará, independentemente de quantos caracteres estranhos bash ( $ , ' , " , etc.) estão lá. Então /dev/sometty simplesmente recebe algum texto.

O problema é que, às vezes, vale a pena eu enviar esses comandos para um arquivo, torná-lo executável, etc., ou em breve: fazer um script e executá-lo a partir do terminal apropriado. Mas isso é muito trabalho. Eu estive pensando em fazer um script para fazer esses arquivos, para uma instrução:

termpipe -e "command1\ncommand2\"command 1 argument\n(s)\"" -t /dev/sometty 

faria algo como:

  1. canaliza os comandos para, digamos, /tmp/termpipe-20140208-153029-1.sh
  2. torna o arquivo executável
  3. executa o arquivo no terminal apropriado
  4. exclua o script quando terminar a execução

AFAIK, o problema está em 3. : isso não resolve nenhum problema, pois eu precisaria de outra instância de termpipe para executar o primeiro no terminal apropriado. E um para aquele. E outra para isso, ad infinitum . Então, isso não pode funcionar. Ou pode? ...

A solução poderia ser usar um pipe nomeado por terminal, e quando cada um inicia, um script diria ao pipe para encaminhar qualquer coisa que receber para o terminal, e então executá-lo (como uma espécie de daemon ).

Acho que isso pode funcionar, mas não sei como configurar o script inicial. Como posso? Como posso dizer ao FIFO para dar comandos canalizados para o respectivo terminal ser executado? Eu não sei muito Bash, então eu apreciaria explicações completas.

    
por JMCF125 08.02.2014 / 17:20

2 respostas

5

Seguindo isso , pode muito bem fazer com que o seu último plano funcione. Para que o comando a ser enviado não seja processado pelo shell, ele deve estar na forma de uma string quando atingir o pipe (assim, echo "command" , não echo 'command' ). Em seguida, ele deve ser lido por um processo em segundo plano ( igualmente um daemon , mas não necessariamente) iniciado no terminal apropriado. Deve ser eval uado pelo mesmo processo.

Mas é boiler-platey para ter um script por canal. Então, vamos generalizar a criação de um script como term-pipe-r.sh (não se esqueça de chmod +x it!):

#!/bin/bash

pipe=$1                     # the pipe name is the first argument
trap 'rm -f "$pipe"' EXIT     # ignore exit and delete messages until the end

if [[ ! -p $pipe ]]; then   # if the pipe doesn't exist, create it
    mkfifo $pipe
fi

while true                  # cycle eternally..
do
    if read line <$ pipe; then
        if [[ "$line" == 'close the term-pipe pipe' ]]; then
            break
            # if the pipe closing message is received, break the while cycle
        fi

        echo                # a line break should be used because of the prompt 
        eval $line          # run the line: as this script should be started
    fi                          # in the target terminal, 
done                            # the line will be run there.

echo "<pipe closing message>"   # custom message on the end of the script

Então diga que você quer que /dev/tty3 receba comandos: vá lá, faça

./term-pipe-r.sh tty3pipe &     # $1 will be tty3pipe (in a new process)

E para enviar comandos, a partir de qualquer terminal (mesmo de si mesmo):

echo "command" > tty3pipe

ou para executar um arquivo lá:

cat some-script.sh > tty3pipe

Observe que esse canal ignora arquivos como .bashrc e os aliases ali, como alias ls='ls --color' . Espero que isso ajude alguém lá fora.

Editar (nota - vantagem do não daemon ):

Acima eu falei sobre o leitor de pipe não ser necessariamente um daemon , mas na verdade, eu verifiquei o diferenças , e acontece que é muito melhor ser um mero processo em segundo plano neste caso. Como dessa forma, quando você fecha o terminal, um sinal EXIT ( SIGHUP , SIGTERM , ou qualquer outro) também é recebido pelo script e o canal é excluído (consulte a linha que começa com trap no script) automaticamente, evitando um processo e arquivo inúteis (e talvez outros se houvesse tal redirecionamento para o pipe inútil).

Editar (automação):

Ainda assim, é chato ter que executar um script que você (eu, pelo menos), provavelmente quer na maioria das vezes. Então, vamos automatizar isso! Deve iniciar em qualquer terminal, e uma coisa que todos eles lêem é .bashrc . Além disso, é uma droga ter que usar ./term-pipe-r.sh . Então, alguém pode fazer:

cd /bin # go to /bin, where Bash gets command names
ln -s /directory/of/term-pipe-r.sh tpr  # call it tpr (terminal pipe reader)

Agora, para executá-lo, você precisará apenas de tpr tty3pipe & in /dev/tty3 sempre que desejar. Mas por que fazer isso quando você pode tê-lo feito automaticamente? Portanto, isso deve ser adicionado a .bashrc . Mas espere: como vai saber o nome do pipe? Pode basear o nome no TTY (que pode ser conhecido com o comando tty ), usando simples REGEX em sed (e alguns truques ). O que você deve adicionar ao ~/.bashrc será então:

pipe="$(sed 's/\/dev\///' <<< 'tty' | sed 's/\///')pipe"
                # ^^^- take out '/dev/' and other '/', add 'pipe'
tpr $pipe &     # start our script with the appropriate pipe name
    
por 08.02.2014 / 22:17
0

Variante do Vim. Vim deve ser o editor padrão.

  1. Escolha um longo comando no histórico, usando as setas para cima / para baixo. Eu escolhi isto: echo "one two three" > new_file.txt
  2. Pressione a combinação Ctrl + x Ctrl + e . Isso abrirá nosso longo comando dentro do Vim. Pressione Ctrl + g , para mostrar o nome do arquivo temporário na parte inferior da janela do vim. No meu caso, é /tmp/bash-fc.230BC2
  3. Vá para outro tty , digite vim /tmp/bash-fc.230BC2 (usando o preenchimento automático de nome de arquivo, é claro). Ele informará que "Arquivo de troca já existe" - pressione O , somente para leitura aberta.
  4. Então, dentro do vim, você precisa da próxima seqüência de chaves: y$ : ! Ctrl+r " Enter
    Explicação :
    • y$ - copia todos os caracteres na linha, exceto a nova linha à direita.
    • : - vá para o modo de linha de comando
    • ! - execute o comando com o shell
    • Ctrl+r " - cole a linha copiada na linha de comando.
    • Enter - execute o comando

Devo mencionar que toda essa sequência de teclas pode ser mapeada para um pressionamento de tecla, por .vimrc file edit.

Está feito - o comando foi copiado de um tty para outro e executado.

    
por 27.05.2017 / 19:32