Espera pela chave no shell script que pode ser canalizada para / bin / bash

3

Considere o seguinte script de shell

echo foo; read; echo bar

Executando bash my_script outputs 'foo', aguarda a tecla de retorno e produz a 'barra'.

Enquanto isso funciona bem assim, não funciona mais se canalizado para / bin / bash:

$ echo 'echo foo;read;echo bar'|bash

gera diretamente 'foo' e 'bar' sem aguardar uma tecla pressionada.

Por que não lê mais o trabalho ao usá-lo dessa maneira?

Existe alguma maneira de reescrever o script de uma forma que funciona como arquivo de script de arquivo, bem como uma string de script canalizada para / bin / bash?

    
por muffel 08.07.2015 / 19:43

3 respostas

2

Isso é realmente fácil, na verdade, Primeiro, você precisa deixar de lado seu stdin em algum descritor lembrado:

exec 9<&0

Lá. Você fez uma cópia. Agora, vamos canalizar nossos comandos no nosso shell.

echo 'echo foo; read <&9; echo bar' | bash

... bem, isso foi fácil. Claro que ainda não terminamos. Nós devemos limpar.

exec 9<&-

Ok, agora terminamos.

Mas podemos evitar a limpeza se agruparmos um pouco nossos comandos ...

{ echo 'echo foo; read <&9; echo bar' | bash; } 9<&0

O descritor só sobrevive enquanto o comando composto designado fizer isso nesse caso.

    
por 09.07.2015 / 08:48
3

O bash builtin read lê stdin (fd0), mas não pode abrir stdin, pois o próprio comando bash já consome stdin.

Você pode eval o que você canaliza

eval 'echo foo;read;echo bar'

Was: Eu não consigo pensar em outra maneira de canalizar um script de shell que ele próprio precise ler de stdin. Quando você canaliza para um shell, esse shell não é interativo.

Eu nunca entendi como duplicar o descritor de arquivo stdin. Veja os microfones respondendo por isso.

BTW .: você pode ver o que acontece com a leitura com

echo 'echo foo;read;echo bar'|strace bash
    
por 08.07.2015 / 19:52
1

A resposta do ikrabbe identifica corretamente porque sua linha de comando não funciona do jeito que você espera. A maneira convencional de invocar um novo shell para uma linha de comando é:

$ sh -c 'echo foo; read; echo bar'

Claro que você pode usar bash se precisar, mas 98% do que você pode querer fazer em um script de shell de uma linha pode ser feito no shell simples. (Não dê atenção ao fato de que "shell velho simples" forma o acrônimo "POS".)

Se o seu objetivo é fazer com que seu script de shell de uma linha seja pausado, esperando por entrada do usuário (possivelmente apenas reconhecimento / confirmação), então é provavelmente o que você deve fazer. Se o seu objetivo é entender melhor o funcionamento do shell, tente isto:

$ (echo 'echo foo; read; echo "$REPLY bar"'; echo candy) | sh
foo
candy bar                               (without waiting)
$
    
por 08.07.2015 / 20:44