Reinsira um programa para stdin

2

Suponha que você queira ter um programa que consuma uma string e depois reconecte stdin quando terminar.

Eu sei que é possível fazer isso com esse truque:

(echo id; cat) | sh

O que funciona bem. Não fecha stdin , pois é usado por cat . Mas a saída é confusa.

Indo mais fundo, entendi que falta um tty .

Se minha compreensão estiver correta, sh estando em um canal não abriu um tty .

O truque que eu encontrei é usar expect .

Basta colocar isso em um arquivo:

spawn sh
reattach

Então, quando cat lhe devolver o controle, faça:

expect exp.sh

Isso é legal porque me dá um tty para fazer tudo que eu preciso: ssh , tmux e assim por diante ...

A única coisa que eu não entendo é porque vejo tudo o que eu digitei, de volta ao meu terminal.

Exemplo:

(echo whoami; cat) | sh
moon
expect exp.sh
spawn sh
sh-3.2$ whoami
whoami
moon

Observe a saída whoami antes do meu login na última linha.

Alguém poderia me explicar por quê? Obviamente, não é uma propriedade de stdout de cat porque está anexada a sh diretamente - sim, mesmo que tenha sido burro tentei o seguinte: (echo id; cat > /dev/null) | sh então nada aconteceu.

Então, é uma propriedade de um tty / pty não exibir de volta o que foi digitado pelo teclado?

    
por tehmoon 21.03.2018 / 12:19

1 resposta

3
{ echo 'exec <&3 3<&-; id' | sh -si; } 3<&0

Parece funcionar com a maioria das implementações sh . Pedimos por um shell interativo com -i (caso contrário, alguns shells o desativariam com base no fato de que stdin não é um dispositivo terminal), inicie com o stdin do shell sendo o pipe, mas com exec <&3 instruí-lo a alterá-lo para o stdin original (externo) que salvamos anteriormente no descritor de arquivo 3 com 3<&0 .

Fazemos isso antes executando id , mas ainda no mesmo comando line , para que stdin seja restaurado para id também. Não importa para id , pois ele não lê seu stdin, mas seria comandos interativos como editores ou shells.

Por que você vê o que você digita em (echo id | cat) | sh . Parece que sua implementação de sh , que parece ser uma versão muito antiga do bash , está sendo executada no modo interativo. Você pode ver isso com o fato de que está emitindo um prompt como se -i fosse usado.

Em seguida, ele implementa seu próprio editor de linhas, mas não desativa o editor de linha próprio do dispositivo tty (porque seu stdin é o pipe e não o dispositivo tty), então você obtém o eco do que digita na linha de dispositivo tty disciplina, e uma vez que você pressiona enter, cat vê todo o conteúdo desse buffer de linha incluindo uma nova linha de uma vez do pipe que ele escreve diretamente para bash , e bash gera o echo do que parte de seu próprio editor de linhas.

Eu suspeito que, se você fez:

stty -icanon -echo; (echo id; cat) | sh; stty sane

Você obteria um comportamento melhor e poderia usar as funcionalidades de edição de linha readline, já que bash receberia todos os caracteres que digitar diretamente conforme eles surgirem.

Para outras opções para que um comando seja executado automaticamente antes que o usuário assuma um shell interativo, consulte:

por 21.03.2018 / 12:48

Tags