如何在Shell脚本中从PostgreSQL中提取pg_backend_pid并将其传递给另一个进程?

3
我需要在命令行(或脚本)上运行bin/psql并打印它的pg_backend_pid,以便将pg_backend_pid作为命令行参数传递给另一个由root运行的进程。对我来说问题是其他进程需要在获取pid后运行。然后psql(具有相同的pid会话)在其他进程启动后运行查询。
诀窍在于Psql需要等待直到其他进程获得pg_backend_pid并且它必须保持相同的会话。
这可以通过shell脚本或perl完成吗?

你实际上想要做什么?bin/psql与Perl脚本有什么关系? - Jonathan Hall
1个回答

11

如果你需要在bash中或者使用带有双向管道的perl,建议使用coprocess。在Python中,你可以使用os.popen2命令;Perl也有通过管道与子进程交互的功能。但是如果有可能,最好使用本地语言数据库驱动程序,例如DBD::Pgpsycopg2

如果一定要在shell中执行此操作,请参考“info bash”并搜索“coprocess”。

以下是一个快速演示用于开始的bash脚本。

#!/bin/bash
set -e -u
DBNAME=whatever_my_db_is_called
coproc psql --quiet --no-align --no-readline --tuples-only -P footer=off --no-password "$DBNAME"
echo 'SELECT pg_backend_pid();' >&${COPROC[1]}
read -u ${COPROC[0]} backend_pid
echo "Backend PID is: ${backend_pid}"
echo "SELECT random();" >&${COPROC[1]}
read -u ${COPROC[0]} randnum
echo "\q" >&${COPROC[1]}
wait %1
echo "Random number ${randnum} generated by pg backend ${backend_pid}"

psql的参数是为了确保它不会暂停输入,不会将制表符或元字符解释为readline命令,并且不会对输出进行漂亮的打印,以便在shell上更容易交互。

或者,你可能根本不需要使用psql,只需要通过某种脚本与PostgreSQL服务器通信。如果是这种情况,使用带有PostgreSQL数据库接口的脚本语言将会更加容易。例如,在Python中:

#!/usr/bin/env python
import os
import sys
import psycopg2

def main():
        conn = psycopg2.connect("dbname=classads")
        curs = conn.cursor()
        curs.execute("SELECT pg_backend_pid();");
        pid = curs.fetchall()[0][0]
        # Do whatever you need to here,
        # like using os.system() or os.popen() or os.popen2() to talk to
        # system commands, using curs.execute() to talk to the database, etc.
        conn.close();

if __name__ == '__main__':
        main()

在Perl中,您可以使用DBI和DBD::Pg来实现类似的效果。


关于你的Bash脚本:如何确保在脚本被Ctrl+C中断时psql/coproc被终止?如何将查询结果输出到一个变量中? - pstanton
@pstanton 很不幸,当父进程退出时,bash子进程通常不会死亡,这是使用明智的语言的另一个原因。但请参见https://aweirdimagination.net/2020/06/28/kill-child-jobs-on-script-exit/。 - Craig Ringer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接