Change it to:
(cat; exec ps -o pid,args) << EOF
$(ps -o pid,ppid,args -H)
EOF
To see what's going on.
With bash
, you'll see:
$ bash ./script
PID PPID COMMAND
428458 428451 /bin/zsh
976353 428458 bash ./script
976354 976353 bash ./script
976355 976354 ps -o pid,ppid,args -H
PID COMMAND
428458 /bin/zsh
976353 bash ./script
976354 ps -o pid,args
$ ksh93u+m ./script
PID PPID COMMAND
428458 428451 /bin/zsh
976559 428458 ksh93u+m ./script
976560 976559 ps -o pid,ppid,args -H
PID COMMAND
428458 /bin/zsh
976559 ksh93u+m ./script
976562 ps -o pid,args
See how in bash
, 976354 (a child of $$
) is the one that forked a child process to run the command-substituted ps
, and later went on to execute ps
, while in ksh, the process that ran the command-substituted ps
was forked by the main ksh process ($$
), so earlier.
pgrep -P "$$"
lists the child processes of the process that executed the shell to interpret your script (but never lists itself). In bash, that happens to include the process that will eventually run your sqlplus
because bash
so happens to do it that way.
Doing it that way makes job control in interactive shells easier, as you can put the command-substituted process in the foreground process group, so it's interrupted as well when you press Ctrl+C, and you'll find that ksh93, when running interactively does it as well when the redirected command is an external command.
But in the case of ksh, at the time pgrep -P
is running, there's not other child of $$
than the one that is running pgrep
itself. The one that will run sqlplus
will be started later, so pgrep
's output will be empty, and your sqlplus
complains about that define=
.
If the point is to have define=<pid>
fed to sqlplus
where <pid>
is the pid of the process that will execute sqlplus
, a more reliable way would be with:
sh -c 'exec sqlplus -s / << EOF
define a=$$
define a
!ptree &a
EOF'
Where, because we use exec
, we know the $$
in that new sh
instance is the process that will execute sqlplus
.