使用Expect和命名管状远程控制SQL*Plus

ZDNet软件频道 时间:2004-04-05 作者:Builder.com |  我要评论()
本文关键词:oracletips
在初始化一个SQL*Plus会话的时候,对shell的访问会受到HOST命令和运行存储的SQL*Plus脚本的限制。
本文译自Builder.com,未经许可请勿转载

在初始化一个SQL*Plus会话的时候,对shell的访问会受到HOST命令和运行存储的SQL*Plus脚本的限制。SQL*Plus不具有别名(alias)或者历史等特性,也不具备把一个命令的输出通过管道传入别的命令的能力。如果能将SQL*Plus的特性添加到现有的shell环境中岂不是一件美事?这里正好有一种方法可以实现这一想法。

在UNIX中,创建一个守护进程来将命令从独立的shell命令传入一个SQL*Plus会话是可能实现的。第一步是创建一样能与SQL*Plus交互环境进行交互的东西。虽然SQL*Plus是可交互的,但是它仅限于STDOUT和STDIN,所以它可以放入一个管道中:

sqlplus /nolog < commands.sql > output.log

然而,如果我们想一次发出一条SQL*Plus命令,那么就需要检查SQL*Plus命令提示符“SQL>”来判断SQL*Plus是否在等待输入,然后使用非阻塞管道,这样我们可以在遇到提示符时停止读取数据而等待SQL*Plus更多的输入。

一种天生可以完成这项工作的脚本描述语言是Expect,它是Tcl/Tk程序设计语言的衍生物。这个进程可以是守护进程或者是服务进程,它接收单个的远程控制命令并将它们传递给从属SQL*Plus会话。要与这个服务进程通信,用法最简单的协议是UNIX Domain Protocol(UDP) sockets。shell可以通过UDP客户端发出命令,然后命令由服务进程接收,然后其结果就通过socket发回到客户端。

Expect需要一个扩展才能够使用UDP sockets。与其安装该扩展到Expect,不如在Perl中使用Expect,因为Perl已经能够很好地处理sockets。在Perl归档中可以找到Expect.pm。这个程序提供在Perl中使用Expect相同的功能。

下面是我的简单示例服务程序,使用Perl、UDP和Expect.pm作为我的行程控制服务程序:

#!/usr/bin/perl -w
# spd.pl - the SQL*Plus daemon server
use strict;
use Expect;
use Socket;

# set up expect
# -- timeout after about 10 minutes
my $timeout = 600;
# -- scan for the SQL*Plus prompt
my $prompt = 'SQL>';
my $exp = new Expect();
$exp->raw_pty(1);
$exp->log_stdout(0);
$exp->spawn('sqlplus','/nolog') || die "unable to spawn sqlplus: $!";
$exp->expect($timeout,'-ex',$prompt) || die $exp->error();
print $exp "set sqlprompt $prompt; ";
$exp->expect($timeout,'-ex',$prompt) || die $exp->error();
$exp->clear_accum();

my $name = "/tmp/sp_$ENV";
unlink($name);
socket(S,PF_UNIX,SOCK_STREAM,0) || die "socket: $!";
bind(S,sockaddr_un($name)) || die "bind: $!";
listen(S,SOMAXCONN) || die "listen: $!";
while(accept(C,S))
{
    # single threaded to avoid confusion
    my $cmd = <C>;
    $cmd =~ s/[ ]*$//g;
    print $exp $cmd," ";
    if ($cmd =~ /^exit$/mi)
    {
        print C "exit. ";
        close C;
        last;
    }
    $exp->expect($timeout,$prompt) || die $exp->error();
    print C $exp->before();
    close C;
}
$exp->soft_close();
close S;
unlink($name);
exit;


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134