Como inserir automaticamente uma string após o prompt

2

Eu tenho uma janela do terminal bash onde executo exclusivamente um comando foo . Por causa disso, eu gostaria que todas as linhas (após o prompt, é claro) começassem com "foo", de modo que eu apenas tivesse que digitar as opções e argumentos das funções, mas não o nome da função recorrente. É claro que seria bom poder alterar a string inserida automaticamente também, mas isso não é essencial para mim.

Exemplo

Quando abro o terminal, sem digitar nada, o que eu quero ver é:

user@host:~/ $ foo 

Então eu digito --option argument e quando pressiono Enter a função foo é chamada com o dado --option e argument .

O que eu tentei

Eu tentei mexer com $PS1 e $PROMPT_COMMAND usando xdotool type "foo " e, surpreendentemente, isso realmente funciona, mas infelizmente ele também imprime “foo” antes do prompt, que é bem feio:

user@host:~/ $ PROMPT_COMMAND='xdotool type "foo "'
foo user@host:~/ $ foo 

Eu também encontrei e tentei a função preexec do script bash-preexec de Ryan Caloras , mas ele tem exatamente o mesmo problema.

Como ecoar (uma string (executável)) para o prompt, para que o cursor pisque no final do line? está relacionada, mas as respostas não permitem adicionar algo ( --option argument ) ao comando a ser executado. Eu não testei zsh - deve haver uma solução bash para uma coisa tão simples, você não acha?

    
por dessert 11.09.2017 / 21:58

2 respostas

4

Com zsh , deve ser apenas uma questão de:

precmd() print -z 'foo '

Ou para evitar a substituição de comandos enfileirados pelo usuário com Alt + q :

zle-line-init() { [ -n "$BUFFER" ] || LBUFFER='foo '; }
zle -N zle-line-init

Com bash , em vez de xdotool , você pode usar o TIOCSTI ioctl :

insert() {
  perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV' -- "$@"
}
PROMPT_COMMAND='insert "foo "'

É preferível que xdotool insira esses caracteres diretamente no buffer de entrada do dispositivo bash está lendo. xdotool só funcionaria se houvesse um servidor X em execução (não funcionaria no console ou terminais reais ou acima de ssh (sem -X ), por exemplo), que é o identificado por $DISPLAY e isso é o que você está interagindo e que o emulador de terminal bash está sendo executado tem o foco quando $PROMPT_COMMAND é avaliado.

Agora, como em seu caso xdotool , porque o ioctl() é feito antes que o prompt seja exibido e a disciplina de linha terminal tty esteja fora do modo icanon+echo por readline, é provável que você veja o < em> echo desse foo pela disciplina de linha tty bagunçando a exibição.

Você poderia contornar isso inserindo uma sequência cujo echo é invisível (como U + 200B se estiver usando exclusivamente localidades Unicode) e vincula-se a uma ação que insira "foo " :

insert() {
  perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV' -- "$@"
}
bind $'"\u200b":"foo "'
PROMPT_COMMAND="insert $'\u200b'"

Ou você pode atrasar o TIOCSTI ioctl o suficiente para a readline ter tempo para inicializar:

insert_with_delay() {
  perl -le 'require "sys/ioctl.ph";
            $delay = shift @ARGV;
            unless(fork) {
              select undef, undef, undef, $delay;
              ioctl(STDIN, &TIOCSTI, $_) for split "", join " ", @ARGV;
            }' -- "$@";
}
PROMPT_COMMAND='insert_with_delay 0.05 "foo "'

Se, como em zsh se aproxima, você deseja manipular o caso em que o usuário digita o texto antes que o prompt seja exibido, você poderia

  • drenar isso fazendo um tcflush(0, TCIFLUSH) em perl antes do TIOCSTI ioctl (também precisa de uma opção -MPOSIX ) ou
  • como na abordagem zsh , certifique-se de que foo esteja inserido no início do buffer inserindo ^A (supondo que você use o modo de edição emacs (padrão), onde ele move o cursor para o início da linha) antes de foo e ^E após (para passar para o final):

    insert_with_delay 0.05 $'foo '
    

    ou

    bind $'"\u200b":"foo "'
    
por 12.09.2017 / 00:48
3

O que você está pedindo não soa muito comum, por isso não é surpreendente que não haja uma maneira direta de fazê-lo.

Com o bash puro, você pode usar o read incorporado para ler a linha e, em seguida, eval para executá-lo. Simule o prompt (estou aproximando seu prompt abaixo).

#!/bin/bash    
PROMPT=$'\e[1m'$USER@$HOSTNAME:$PWD$' $ \e[0m'
IFS= read -r -e -i "foo " -p "$PROMPT" line
eval "$line"
exit

Coloque isso em um script e diga ao seu emulador de terminal para executar esse script.

Como alternativa, execute Screen no emulador de terminal. Você pode usar seu comando stuff para simular a entrada.

    
por 11.09.2017 / 22:20