A similar script, without sudo
, but similar results:
$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami
$ bash < script.sh
--whoami
$ dash < script.sh
itvirta
With bash
, the rest of the script goes as input to sed
, with dash
, the shell interprets it.
Running strace
on those: dash
reads a block of the script (eight kB here, more than enought to hold the whole script), and then spawns 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|...
Which means that the filehandle is at the end of the file, and sed
will not see any input. The remaining part being buffered within dash
. (If the script was longer than the block size of 8 kB, the remaining part would be read by sed
.)
Bash, on the other hand, seeks back to the end of the last command:
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|...
If the input comes from a pipe, as here:
$ cat script.sh | bash
rewinding cannot be done, as pipes and sockets are not seekable. In this case, Bash falls back to reading the input one character at a time to avoid overreading. (fd_to_buffered_stream()
in input.c
) Doing a full system call for each byte is not very effective in principle. In practise, I don't think the reads will be a great overhead compared e.g. to the fact that most things the shell does involve spawning whole new processes.
A similar situation is this:
echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'
The subshell has to make sure read
only reads up the the first newline, so that head
sees the next line. (This works with dash
too.)
In other words, Bash goes to additional lengths to support reading the same source for the script itself, and for commands executed from it. dash
doesn't. The zsh
, and ksh93
packaged in Debian go with Bash on this.
sudo su
: http://unix.stackexchange.com/questions/218169/is-there-ever-a-good-reason-to-run-sudo-su – Kusalananda Apr 12 '17 at 20:07/bin/sh
on (my copy of) Debian is Dash, yes. I didn't even know what that was until just now. I've stuck with bash until now. – devoutsalsa Apr 12 '17 at 20:22user-switch.sh
in a Jenkins job, and it the script executed. Running the same script outside of Jenkins produced different results, and I resorted to file redirection to get the behavior I saw in Jenkins. – devoutsalsa Apr 13 '17 at 22:36