这是一个简化的示例:
脚本1
#!/bin/bash
./script2
脚本2
#!/bin/bash
foo() {
parent_script=$(ps -o comm= $PPID)
echo "Parent script: $parent_script" > log
}
foo &
日志内容(运行 script1 后):
父脚本:
我可以通过将函数设置为非后台函数或获取函数外部的父脚本名称并将其作为参数传递来解决此问题:
脚本2
#!/bin/bash
foo() {
echo "Parent script: $1" > log
}
parent_script=$(ps -o comm= $PPID)
foo "$parent_script" &
日志内容(运行 script1 后):
父脚本:script1
更奇怪的是,如果我只是在原来的行sleep 1
后面添加一个,我也会得到预期的结果:foo &
script2
#!/bin/bash
foo() {
parent_script=$(ps -o comm= $PPID)
echo "Parent script: $parent_script" > log
}
foo &
sleep 1
但是我想知道1)为什么第一个示例不起作用,2)有没有办法从后台函数内部获取父脚本名称?
解决为什么
sleep 1
有效...对于示例脚本,父进程很有可能在子进程生成子 shell 来运行
ps
. (生成子外壳确实需要一些时间)当子进程最终运行时,
ps
它发现父进程不再存在。这
sleep 1
将使父进程保持活动状态足够长的时间,以便子进程a)生成子 shell 和b)运行 'successful'ps
。该函数被发送到后台这一事实并没有固有的问题,问题是脚本不执行任何其他操作,因此在函数运行
ps
.因此,如果脚本有更多工作要做,确保在执行函数时它仍然在运行,那么即使在后台,该函数也能正常工作。结论:如果不向主脚本添加更多步骤,就无法使其在后台工作,因为
ps
当将其发送到后台时,父级始终会在运行之前退出。获取父脚本名称的另一个选项是
$0
在父脚本内部捕获(脚本名称)。然后可以将其作为命令行参数或通过导出变量传递给子进程,例如:
测试:
注意这两种情况都
$0
包含路径组件;如果不需要路径组件,我们可以使用参数替换来删除路径:注意:我们可以改为使用
export parent=$(basename "$0")
,但通过参数替换,无需生成子 shell(以捕获调用结果basename
)测试:
这种方法有几个好处:
ps
调用的输出