Um script semelhante, sem sudo
, mas resultados semelhantes:
$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami
$ bash < script.sh
--whoami
$ dash < script.sh
itvirta
Com bash
, o restante do script entra como entrada para sed
, com dash
, o shell o interpreta.
Executando strace
sobre eles: dash
lê um bloco do script (oito kB aqui, mais do que suficiente para manter todo o script) e, em seguida, gera sed
:
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 8192) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
O que significa que o filehandle está no final do arquivo e sed
não verá nenhuma entrada. A parte restante sendo armazenada em buffer em dash
. (Se o script fosse maior que o tamanho de bloco de 8 kB, a parte restante seria lida por sed
.)
Bash, por outro lado, busca voltar ao final do último comando:
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 36) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
...
lseek(0, -7, SEEK_CUR) = 29
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
Se a entrada vem de um pipe, como aqui:
$ cat script.sh | bash
O rebobinamento não pode ser feito, pois canos e soquetes não são procurados. Neste caso, o Bash volta a ler a entrada um caractere de cada vez para evitar a sobreposição. ( fd_to_buffered_stream()
in input.c
) Fazendo uma chamada completa do sistema para cada byte não é muito eficaz em princípio. Na prática, não creio que as leituras sejam um grande gasto comparativamente, por ex. ao fato de que a maioria das coisas que o shell envolve envolve a criação de novos processos.
Uma situação semelhante é esta:
echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'
O subshell precisa garantir que read
apenas leia a primeira nova linha, para que head
veja a próxima linha. (Isso funciona com dash
também.)
Em outras palavras, o Bash vai a comprimentos adicionais para suportar a leitura da mesma fonte para o próprio script e para os comandos executados a partir dele. dash
não. O zsh
e ksh93
empacotados no Debian vão com o Bash.