0

Korn script:

#!/bin/ksh
sqlplus -s / << EOF
define a=$(pgrep -P $$)
define a
!ptree &a
EOF

VS

Bash script:

#!/bin/bash
sqlplus -s / << EOF
define a=$(pgrep -P $$)
define a
!ptree &a
EOF

Korn shell output (doesn't work as expected):

$ /tmp/testsql.ksh
SP2-0137: DEFINE requires a value following equal sign
SP2-0135: symbol a is UNDEFINED
Enter value for a:
SP2-0546: User requested Interrupt or EOF detected.

Bash shell output (works as expected):

$ /tmp/testsql.bash
DEFINE A               = "2713" (CHAR)
  710 /usr/lib/ssh/sshd
   9574 /usr/lib/ssh/sshd -R
     9578 /usr/lib/ssh/sshd -R
.
.
.
                     2712 /bin/bash /tmp/testsql.sh
                       2713 sqlplus -s /
                         2717 ptree 2713

Any ideas how to make this work in ksh script?

1
  • define is sqlplus command to define a variable. Nothing to do with alias.
    – Ray
    Aug 20, 2021 at 4:20

1 Answer 1

1

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.

1
  • Thanks Stephane, I knew that ksh was doing command substitution expansion $() even before running sqlplus hence the child process returning null value. Your explanation was spot on, exec works like a charm in this case.
    – Ray
    Aug 21, 2021 at 10:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .