Re: 'wait' in command group in pipeline fails to recognize child process
On 6/23/21 6:24 AM, Chet Ramey wrote: On 6/22/21 9:54 PM, Martin Jambon wrote: In the posix definition, a subshell - is not necessarily implemented as a separate process - belongs to a unique shell - is not a shell Why is it not "a shell?" Because '$$' doesn't match its process ID. What is the magic quality that imparts shellness? '$$' matching the process ID. Posix: '$' shall expand to the same value as that of the current shell. (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02) Bash: ($$) Expands to the process ID of the shell. (https://www.gnu.org/software/bash/manual/bash.html#Special-Parameters) I'm not sure why I have to fight over this. It's clearly my misunderstanding. That's why I suggest clarifications in the documentation, if you're interested in creating a better experience for users like me.
Re: 'wait' in command group in pipeline fails to recognize child process
On 6/22/21 6:11 PM, Lawrence Velázquez wrote: On Tue, Jun 22, 2021, at 8:52 PM, Martin Jambon wrote: It's better. However, the reader is still left wondering what "the shell" is referring to in first sentence. Subshells aside, I have a hard time believing that "the process ID of the shell" confuses anybody in practice. Even POSIX doesn't overcomplicate this: $ Expands to the decimal process ID of the invoked shell. In a subshell (see Shell Execution Environment), '$' shall expand to the same value as that of the current shell. (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02) This language implies that a subshell is part of the shell but not a shell in itself. This is what I pointed out earlier but I received a conflicting answer. This is confirmed by this definition from posix: A subshell environment shall be created as a duplicate of the shell environment, except that signal traps that are not being ignored shall be set to the default action. Changes made to the subshell environment shall not affect the shell environment. Command substitution, commands that are grouped with parentheses, and asynchronous lists shall be executed in a subshell environment. Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment. (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12) In the posix definition, a subshell - is not necessarily implemented as a separate process - belongs to a unique shell - is not a shell This makes the term "the shell" unambiguous to a reader who's aware of this - but it's obvious to me that "subshell" should be clarified in the context of '$$'. A subset is a set, a subgroup is a group, a subtype is a type, a subtree is a tree, a subprocess is a process. However a submarine is not a marine, and a subshell is not a shell (sea stuff!). Anyway, I left a suggestion to revise the documentation for '$$' in my previous email. That's the best I can produce at this time. Martin
Re: 'wait' in command group in pipeline fails to recognize child process
On 6/22/21 5:00 PM, Lawrence Velázquez wrote: Maybe something like this would get the point across: ($$) Expands to the process ID of the shell. In a subshell, it expands to the value that $$ has in the invoking shell. It's better. However, the reader is still left wondering what "the shell" is referring to in first sentence. Here's my next suggestion, which borrows some language from the documentation for BASHPID: ($$) Expands to the ID of the process that initialized Bash. The value of $$ is inherited in subshells, such as pipelines, regardless of their own process ID. See also the Bash variable BASHPID. For reference, the documentation for 'BASHPID' is this: Expands to the process ID of the current Bash process. This differs from $$ under certain circumstances, such as subshells that do not require Bash to be re-initialized. Assignments to BASHPID have no effect. If BASHPID is unset, it loses its special properties, even if it is subsequently reset.
Re: 'wait' in command group in pipeline fails to recognize child process
On 6/22/21 1:37 PM, Greg Wooledge wrote: On Tue, Jun 22, 2021 at 01:12:10PM -0700, Martin Jambon wrote: On 6/22/21 4:31 AM, Greg Wooledge wrote: A pipeline creates two or more subshells, one for each command in the pipeline. Therefore, your wait command is running in a different process than the one which created the sleep background job. The curly braces are irrelevant here. unicorn:~$ sleep 1 & wait "$!"|cat [1] 1290127 bash: wait: pid 1290127 is not a child of this shell Thank you! Now I know that a subshell is not a shell, $$ being the process ID of the shell, not of the subshell. It's a forked child process of bash, and as such, it's still a shell. Specifically, it's bash. There's some formal definition that you can ignore. The real definition of a subshell is "the direct result of a fork()". It inherits all of the shell variables, functions, aliases, and so on that the parent shell process had at the time of the fork. This is different from a direct call to "bash", which would not inherit shell variables and so on -- only environment variables. Great, then I would change the documentation of '$$'. Currently it says this: ($$) Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the invoking shell, not the subshell. This first mentions just "the shell". I suggest calling it the "root shell" instead, i.e. the process where "exec bash" took place. I would also mention pipelines here, since these are more commonly used than () subshells. I don't know if there are other ways of creating subshells. If that's all, I think it would be valuable to mention those two cases rather than just one. Well, I suppose "root shell" could be misunderstood as a shell run by the 'root' user but this doesn't make much sense in this context. I can't find a better name. Here's how we might change the description of '$$': ($$) Expands to the process ID of the root shell. In a pipeline or in a () subshell, it expands to the process ID of the root shell, not the subshell. I also changed "invoking shell" to "root shell" because the invoking shell or parent shell is not necessarily the same as the root shell e.g. $ echo $$; (echo $$; (echo $$)) 688918 688918 688918 In the pipeline, there are two subshells created. One of them runs the command wait "$!", and the other runs the command cat. The special parameter $! is inherited from the parent shell, and contains the PID of the sleep process that the parent shell created. But the child subshell can't wait for that process, because it belongs to someone else. Hence the error message. Yup. I think the error message is clear. No complaint about that.
Re: 'wait' in command group in pipeline fails to recognize child process
On 6/22/21 4:31 AM, Greg Wooledge wrote: On Tue, Jun 22, 2021 at 02:42:40AM -0700, Martin Jambon wrote: I ran into something that looks like a bug to me, although I'm not super familiar curly-brace command groups. Bash version: latest from GitHub mirror (commit ce23728: Bash-5.1 patch 7) Minimal repro: $ sleep 1 & { wait $!; } | cat [1] 665454 bash: wait: pid 665454 is not a child of this shell I was expecting a success, just like we get without the pipeline: A pipeline creates two or more subshells, one for each command in the pipeline. Therefore, your wait command is running in a different process than the one which created the sleep background job. The curly braces are irrelevant here. unicorn:~$ sleep 1 & wait "$!"|cat [1] 1290127 bash: wait: pid 1290127 is not a child of this shell Thank you! Now I know that a subshell is not a shell, $$ being the process ID of the shell, not of the subshell.
Re: 'wait' in command group in pipeline fails to recognize child process
On 6/22/21 6:15 AM, Chet Ramey wrote: On 6/22/21 5:42 AM, Martin Jambon wrote: Hello! I ran into something that looks like a bug to me, although I'm not super familiar curly-brace command groups. It's not the brace command; it's the pipeline. Thank you! It's the $$ that confused me since I thought incorrectly that it would print the current process ID. I was also misled by the term "subshell" which is not a proper shell like a subprocess is just another process.
'wait' in command group in pipeline fails to recognize child process
Hello! I ran into something that looks like a bug to me, although I'm not super familiar curly-brace command groups. Bash version: latest from GitHub mirror (commit ce23728: Bash-5.1 patch 7) Minimal repro: $ sleep 1 & { wait $!; } | cat [1] 665454 bash: wait: pid 665454 is not a child of this shell I was expecting a success, just like we get without the pipeline: $ sleep 1 & { wait $!; } [1] 665591 [1]+ Donesleep 1 The following scripts are similar but print PIDs along the way: failing script $ cat wait-for-child echo "main pid: $$" /usr/bin/sleep 1 & job_pid=$! echo "job pid: $job_pid" { echo "command group pid: $$" wait "$job_pid" || echo "wait failed!" } | cat Output: $ ./bash wait-for-child main pid: 664755 job pid: 664756 wait-for-child: line 7: wait: pid 664756 is not a child of this shell command group pid: 664755 wait failed! ^ We see that the current PID in the command group is the same as in the rest of the shell, as it should be. It is unclear to me why 'wait' believes that the background job's PID is not of a child. successful script Compare to the same script without having the command group in a pipeline (I removed '| cat'): $ cat wait-for-child-ok echo "main pid: $$" /usr/bin/sleep 1 & job_pid=$! echo "job pid: $job_pid" { echo "command group pid: $$" wait "$job_pid" || echo "wait failed!" } $ ./bash wait-for-child-ok main pid: 664705 job pid: 664706 command group pid: 664705 ^ OK Martin