使用 Heredoc 并引用 shell PID 的命令替换在 ksh 和 bash 之间有所不同

使用 Heredoc 并引用 shell PID 的命令替换在 ksh 和 bash 之间有所不同

科恩脚本:

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

VS

重击脚本:

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

Korn shell 输出(未按预期工作):

$ /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 输出(按预期工作):

$ /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

有什么想法可以让这个在 ksh 脚本中工作吗?

答案1

将其更改为:

(cat; exec ps -o pid,args) << EOF
$(ps -o pid,ppid,args -H)
EOF

看看发生了什么事。

使用bash,您将看到:

$ 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

看看在 中bash,976354 ( 的子进程$$) 是如何派生出一个子进程来运行命令替换的ps,然后继续执行ps,而在 ksh 中,运行命令替换的进程ps是由主 ksh 派生的处理( $$),所以更早。

pgrep -P "$$"列出执行 shell 来解释脚本的进程的子进程(但从不列出其自身)。在 bash 中,这恰好包括最终将运行你的进程,sqlplus因为bash恰好就是这样做的。

这样做可以使交互式 shell 中的作业控制更容易,因为您可以将命令替换的进程放在前台进程组中,因此当您按 Ctrl+C 时它也会被中断,并且您会发现 ksh93 在交互运行时当重定向命令是外部命令时也会执行此操作。

但就 ksh 而言,在运行时,除了正在运行的子进程之外,pgrep -P没有其他子进程。将要运行的那个将稍后启动,因此输出将为空,并且您对此抱怨。$$pgrepsqlpluspgrepsqlplusdefine=

如果重点是要define=<pid>提供sqlplus<pid>要执行的进程的 pid sqlplus,则更可靠的方法是:

sh -c 'exec sqlplus -s / << EOF
define a=$$
define a
!ptree &a
EOF'

其中,因为我们使用exec,所以我们知道$$该新sh实例中的 是将要执行的进程sqlplus

相关内容