3 ms·
The Unix V6 shell and how control flow worked in it
- bawolff 3y ago> The V6 shell didn't have control flow constructs as such; instead it outsourced them to external commands, such as goto(1), exit(1) and if(1). The goto and exit commands worked by changing the seek offset in the shell script, which worked because the V6 shell didn't use buffered input; it read its input line by line That's wild
- rightbyte 3y agoYou can modify Windows bat-files too while executing them. Like append stuff to them. Quite useful. foo.sh: echo "echo foobar" >> foo.sh echo "Will it print?" =)
- jmmv 3y ago> which worked because the V6 shell didn't use buffered input; it read its input line by line Isn't this the case still, though? I've been bitten by this many times: start a long-running script, modify it in the meantime, and see the running script crash due to syntax errors and the like.
- xyzzy_plugh 3y agoNot quite the same thing. The old shell would stop reading at `\n`, whereas buffered input means the process has an arbitrary buffer of bytes read ahead. Modifying the file while it's executing would cause issues in either scenario, so long as any part of the file was unbuffered. I think you're interpreting buffering to mean "buffer the entire file" which isn't what happens here.
- kragen 3y agodash 0.5.12-2 line buffers, haven't tested bash you see this happen even in very small shell scripts
- rwmj 3y agoThat's the way current shells work. They do actually use buffered input, but they use lseek on the input so each time they always read the next command from the file. You can prove this fairly easily: $ cat input.sh echo hello sleep 10 echo world During the sleep, edit input.sh and change "world" to something else. It will print the something else. It should be possible to implement goto etc as external commands, although of course somewhat inefficient and unnecessary.
- abecedarius 3y agoHow could the external command change the seek offset in its parent process? Did the seek system call change it in both? (I guess I've forgotten most of what I ever knew about Unix system calls.)
- ithkuil 3y agoYes, that's what sharing a file descriptor means. You could have two file descriptors pointing to the same file (either by opening the same file or by duplicating the file descriptor with the dup syscall) and in that case the two file descriptors would have each their own file position
- abecedarius 3y agoThanks. I'm still surprised because in my fuzzy memory the shell after forking keeps only the stdin/stdout/stderr fds open by the time it execs the command -- but it makes sense that you could arrange to make this work with a different setup. BTW if we're making changes like that, you could also make I/O redirection the responsibility of a command instead of the shell, similar to this article's 'if' command. I wonder how much else you could take out of the shell.
- ithkuil 3y agoThe O_CLOEXEC flag of open (and FD_CLOEXEC flag of fctl) can help you control which file descriptors will be automatically closed on exec. Otherwise, you have to manually close the files between a fork and an exec.
- imglorp 3y agoAnother interesting simplification of old shells was they implemented functions by saving their bodies as individual scripts in a temp directory, which got prepended to the path. Each used $1, $2 etc and return/echo as normal to interact with the parent shell.