[Toybox] Would someone please explain what bash is doing here?

Rob Landley rob at landley.net
Wed May 27 11:07:59 PDT 2020

On 5/23/20 5:51 PM, Chet Ramey wrote:
> On 5/23/20 1:11 PM, Rob Landley wrote:
>> Starting to open the job control can of worms, and:
>>   $ while true; do readlink /proc/self | cat - $$; done
>>   24658
>>   cat: 20032: No such file or directory
>>   24660
>>   cat: 20032: No such file or directory
>>   24662
>> Is calling readlink and cat each time through the loop (true is a builtin), so
>> the pid advances by 2 and the pipeline is NOT a subshell. 
> Correct. Each element of a pipeline is executed in a subshell.

  $ sleep 10 | cat; echo hello
  [1]+  Stopped                 sleep 10 | cat
  $ fg
  sleep 10 | cat
  $ sleep 10 | cat && echo hello
  [1]+  Stopped                 sleep 10 | cat
  $ fg
  sleep 10 | cat
  $ sleep 10 | cat || echo hello
  [1]+  Stopped                 sleep 10 | cat
  $ fg
  sleep 10 | cat

Ok, I was trying to figure out what "jobs" should display when the pipeline it
stopped is held together by && and || rather than just by | and... apparently
you need parentheses or curly brackets to get it to do that, because suspended
commands exit 'false' immediately and the rest of the line continues?

  $ { echo hello; sleep 3; echo there; } | cat
  [1]+  Stopped                 { echo hello; sleep 3; echo there; } | cat
  $ fg
  { echo hello; sleep 3; echo there; } | cat

Right. So it CAN include more stuff, it just doesn't. And instead the stuff
RESUMES. (Is that posix what posix says to do? Does a shell script differ from
interactive behavior here?)

Ok, I guess pipeline has the tty (doo dah, doo dah) so signals go to it, but...

  $ sleep 10 || echo potato
  landley at driftwood:~/toybox/toybox$ sleep 10 | cat || echo potato

That kills the later commands too? The interrupted command didn't just exit, it
killed pending commands after it.

  $ sleep 10 || echo hello
  [1]+  Stopped                 sleep 10

Ok, it's not a pipeline thing, individual commands do it too. Suspend behavior
is that the command that was suspended exited false immediately and the rest of
the line resumes as if it exited with an error...

  $ sleep 10; echo $?
  [2]+  Stopped                 sleep 10

Specifically it exited "killed by SIGSTOP" except it wasn't _killed_...

But CTRL-C behavior is to _not_ to have the command exit "killed by 3" and
resume the rest of the script, instead all pending processing is flushed.

Right. Am I gonna have to go read posix again? I dowanna read posix again.

(And THIS is why I've held off on implementing job control because I have no
current idea how to REGRESSION TEST this mess. I need to write a pty
master/slave pair that sends synthetic signals down the pipeline from a virtual
terminal, and that's a CAN OF WORMS. I wonder if I can make puppy eyes at Rich
Felker to do it, he wrote http://git.musl-libc.org/cgit/uuterm/ way back when,
and don't ask me why that's _not_ on his github...)

The man page says "delayed suspend character" (CTRL-Y) is a thing, but as far as
I can tell it isn't. This was some GNU Hurd feature maybe?

The man page has more "written by somebody who already knows it" stuff:

       referred to as %n.  A job may also be referred to using a prefix of the
       name used to start it, or using a substring that appears in its command
       line.  For example, %ce refers to  a  stopped  ce  job.   If  a  prefix
       matches  more  than one job, bash reports an error.  Using %?ce, on the
       other hand, refers to any job containing the string ce in  its  command
       line.   If  the  substring  matches  more than one job, bash reports an

That "%?ce" is a specific example, not an explanation of what's happening here.
Is it because "?" is a wildcard, or because %? is a special prefix? That
question mark isn't going to act as a wildcard and match a filesystem character
during normal wildcard processing, right? If there's a %xce in the current
directory, it won't resolve to that? The % is parsed _before_ wildcards and
suppresses normal wildcard expansion? If a $variable expands to %?ce does it
still count? How does this interact with quoting? Is kill "%?ce" different from
kill %?ce or are they the same?

Ordinarily I would start assembling a list of regression tests to add to sh.test
to determine/demonstrate the behavior I need to implement, but... backgrounding!
Asynchronous! Not really designed to be scripted!



P.S. When you background something, what is the [1] 12345 printing _to_? I've
redirected stdout and stderr and neither one affect it, it seems to go straight
to /dev/tty? Ah, nope, figured it out:

  $ { sleep 3& } 2> bllorp

It's stderr but redirects get unwound before the report so you need { }

More information about the Toybox mailing list