Um script semelhante, sem sudo
, mas com 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 é usado como entrada para sed
, com dash
, o shell o interpreta.
Executando strace
neles: dash
lê um bloco do script (oito kB aqui, mais do que suficiente para armazenar todo o script) e depois 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 identificador de arquivo está no final do arquivo e sed
não verá nenhuma entrada. A parte restante está sendo armazenada em buffer dash
. (Se o script for maior que o tamanho do bloco de 8 kB, a parte restante será lida por sed
.)
Bash, por outro lado, procura 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 vier de um tubo, como aqui:
$ cat script.sh | bash
não é possível rebobinar, pois não é possível procurar tubos e soquetes. Nesse caso, o Bash volta a ler a entrada, um caractere de cada vez, para evitar a substituição. ( fd_to_buffered_stream()
ininput.c
) Fazer uma chamada de sistema completa para cada byte não é muito eficaz em princípio. Na prática, não acho que as leituras sejam uma grande sobrecarga em comparação, por exemplo, ao fato de que a maioria das coisas que o shell envolve gera processos totalmente novos.
Uma situação semelhante é a seguinte:
echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'
O subshell deve garantir que read
apenas leia a primeira nova linha, para head
ver a próxima linha. (Isso funciona dash
também.)
Em outras palavras, o Bash se esforça para dar suporte à leitura da mesma fonte para o próprio script e para comandos executados a partir dele. dash
não. O zsh
e ksh93
empacotado em Debian ir com Bash sobre este assunto.
sudo su
: unix.stackexchange.com/questions/218169/…