Parar script bash com qualquer chave

1

Estou escrevendo um perfil de terminal gnome personalizado que desejo parar com qualquer chave que eu escolher. Depois de pressionar a tecla, minha intenção é completar todos os meus comandos naquele momento e começar o su. Eu tentei adicionar um & ao meu comando, mas não funcionou. Estou anexando algumas informações:

MEU CÓDIGO:

su --command 'read -n 1 -s key; if [ "$key" == "g" ]; then su; fi;'
echo -n "W" 
sleep 0.09
echo -n "e" 
sleep 0.09
echo -n "l"
sleep 0.09
echo -n "c"
sleep 0.09
echo -n "o"
sleep 0.09 
echo -n "m"
sleep 0.09 
echo -n "e"  
sleep 0.09 

RESULTADO ESPERADO:

[caracteres sendo ecoados corretamente até ...]

[tecla pressionada]

Welcome

root@myuser:~#
    
por xvlaze 06.02.2016 / 17:07

2 respostas

0

Isso não funciona em muitos níveis. Principalmente, o bash não é muito bom para programação multi-threaded. Mas se você for fazer assim, você tem que perceber duas coisas: (1) para que o seu "thread" de leitura de chave funcione, ele tem que ter acesso exclusivo ao tty. (2) Quando você coloca um processo em segundo plano, ele irá naturalmente copiar stdin do processo atual 'tty. (3) Normalmente, o shell detecta isso e interrompe o processo em segundo plano.

Only foreground processes are allowed to read from or, if the user so specifies with stty tostop, write to the terminal. Background processes which attempt to read from (write to when stty tostop is in effect) the terminal are sent a SIGTTIN (SIGTTOU) signal by the kernel's terminal driver, which, unless caught, suspends the process.

Você pode ver isso aqui:

otheus@otheus-VirtualBox ~ $ ( while true; read x; do echo $x; done; ) &
[1] 2841
otheus@otheus-VirtualBox ~ $ 

[1]+  Stopped                 ( while true; read x; do
    echo $x;
done )

Portanto, o processo de leitura de tty deve estar em primeiro plano. O background pode fazer o "trabalho", mas certifique-se de fechar o stdin primeiro: <&-

Para parar o processo "trabalhador", você terá que conhecer o seu pid. Para fazer isso, você precisa ativar o controle de tarefas dentro de um script (está desativado por padrão). set -m faz isso. Inicie e mate %- após o pressionamento de tecla. Você pode querer certificar-se de que o loop de pressionamento de tecla termina quando o trabalhador faz. Você faz seu segmento de monitor de chave:

start_worker &

while jobs %- &>/dev/null; do 
   read -n 1 -s -t 1 key
   # test key
   if [[ $key == q ]]; then
      kill -1 %-
      break
   fi
fi
wait

A condição while testa se o trabalho ainda está sendo executado / reconhecido. Quando terminar, os trabalhos retornarão false e o loop será encerrado. O comando de leitura agora também expira após 1 segundo. Finalmente, depois que o loop sair, espere para ter certeza de que o trabalho está "limpo". (Se você tiver outros trabalhos em execução, isso irá parar aqui.)

A outra coisa é: o que você está tentando realizar é inerentemente perigoso. A mistura de acesso root e bash scripting é perigosa . Existem alguns tópicos para abordar aqui, como o que acontece quando o usuário acessa Control-C ou Ctl-Z.

Por último, não tenho certeza se você pode misturar o segmento de trabalho com su como no seu exemplo. Quando o su é executado, ele alterará o tty atual para o root, impedindo que o thread de trabalho seja enviado para ele.

    
por 06.02.2016 / 19:30
0

O mais próximo que eu poderia ter um problema parecido foi algo assim ...

Primeiro, crie um script chamado inputproc:

read -n1

Em seguida, crie um script chamado mainscript:

array=(W e l c o m e)
buf=0
while pgrep "inputproc" > /dev/null; do
    echo -n ${array[buf]}
    ((buf++))
    sleep 0.09
done
#Insert any commands you want to run afterwards here...

Depois, execute-os com este comando

./mainscript & ./inputproc

E bem, isso faz exatamente o que você queria. Não consegui encontrar uma maneira de fazer isso com apenas um script, mas surpreendentemente, descobri uma maneira de fazer isso com apenas uma janela de terminal.

Além do óbvio (usando um loop while para verificar se inputproc está sendo executado antes de cada comando echo, e usando uma matriz para fazer eco das letras desejadas em ordem) isso funciona executando mainscript em segundo plano enquanto executa inputproc em primeiro plano. Não é sem falhas, mas é o mais próximo que você pode chegar ao seu resultado desejado, acredito.

    
por 06.02.2016 / 18:03