在PostgreSQL中使用 plpythonu 调用系统命令
背景
有些时候,为了方便调度,可能需要在数据库中执行一些系统命令。
例如清理OSS对象存储,查看磁盘使用量等。
使用plpythonu,可以简便的调用系统命令。
例子
1、执行命令,返回命令的返回值。
create or replace function exec_cmd1(cmd text) returns int as $$
import os
v = os.system('ls ' + cmd)
return v
$$ language plpythonu;
2、执行命令,返回命令的标准输出。
create or replace function exec_cmd2(cmd text) returns setof text as $$
import os
v = os.popen('ls ' + cmd)
return v
$$ language plpythonu;
3、查询举例
postgres=# select exec_cmd1('-laZ /data01') ;
exec_cmd1
-----------
0
(1 row)
postgres=# select rtrim(exec_cmd2('-laZ /data01'), E'\n') ;
rtrim
----------------------------------------------------------------------------
drwxr-xr-x root root ? .
dr-xr-xr-x. root root system_u:object_r:root_t:s0 ..
drwx------ root root ? lost+found
drwx------ postgres postgres ? pg_root1921
drwx------ postgres postgres ? pg_root1922
drwxr-xr-x postgres postgres ? pg_rpm
(6 rows)
安全
1、小心注入,与SQL注入类似例子:
postgres=# select rtrim(exec_cmd2('-laZ /data01; df -h;'), E'\n') ;
rtrim
----------------------------------------------------------------------------
drwxr-xr-x root root ? .
dr-xr-xr-x. root root system_u:object_r:root_t:s0 ..
drwx------ root root ? lost+found
drwx------ postgres postgres ? pg_root1921
drwx------ postgres postgres ? pg_root1922
drwxr-xr-x postgres postgres ? pg_rpm
文件系统 容量 已用 可用 已用% 挂载点
/dev/vda1 40G 2.6G 35G 7% /
devtmpfs 487M 0 487M 0% /dev
tmpfs 497M 108K 497M 1% /dev/shm
tmpfs 497M 388K 496M 1% /run
tmpfs 497M 0 497M 0% /sys/fs/cgroup
/dev/vdb1 200G 3.6G 197G 2% /data01
tmpfs 100M 0 100M 0% /run/user/0
(14 rows)
参考
python调用Shell脚本:os.system(cmd)或os.popen(cmd)
python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容。实际使用时视需求情况而选择。
现假定有一个shell脚本test.sh:
#!/bin/bash
1. echo "hello world!"
2. exit 3
os.system(cmd):
该 方法在调用完shell脚本后,返回一个16位的二进制数,低位为杀死所调用脚本的信号号码,高位为脚本的退出状态码,即脚本中“exit 1”的代码执行后,os.system函数返回值的高位数则是1,如果低位数是0的情况下,则函数的返回值是0×100,换算为10进制得到256。
如果我们需要获得os.system的正确返回值,那使用位移运算可以还原返回值:
1. >>> n = os.system(test.sh)
2. >>> n >> 8
3. >>> 3
os.popen(cmd):
这种调用方式是通过管道的方式来实现,函数返回一个file-like的对象,里面的内容是脚本输出的内容(可简单理解为echo输出的内容)。使用os.popen调用test.sh的情况:
python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容。实际使用时视需求情况而选择。
明显地,像调用”ls”这样的shell命令,应该使用popen的方法来获得内容。