您现在的位置是:首页 >

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

火烧 2021-09-16 18:07:20 1046
使用Ex ect和命名管状远程控制SQL*Plu   在初始化一个SQL*Plu 会话的时候 对 hell的访问会受到HOST命令和运行存储的SQL*Plu 脚本的限制 SQL*Plu 不具有别名(a

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

管状发鞘 使用Expect和命名管状远程控制SQL*Plus
  在初始化一个SQL*Plus会话的时候 对shell的访问会受到HOST命令和运行存储的SQL*Plus脚本的限制 SQL*Plus不具有别名(alias)或者历史等特性 也不具备把一个命令的输出通过管道传入别的命令的能力 如果能将SQL*Plus的特性添加到现有的shell环境中岂不是一件美事?这里正好有一种方法可以实现这一想法     在UNIX中 创建一个守护进程来将命令从独立的shell命令传入一个SQL*Plus会话是可能实现的 第一步是创建一样能与SQL*Plus交互环境进行交互的东西 虽然SQL*Plus是可交互的 但是它仅限于STDOUT和STDIN 所以它可以放入一个管道中     sqlplus /nolog < mands 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 minutes  my $timeout = ;  # scan for the SQL*Plus prompt  my $prompt = SQL> ;  my $exp = new Expect();  $exp >raw_pty( );  $exp >log_stdout( );  $exp >spawn( sqlplus /nolog ) || die unable to spawn sqlplus: $! ;  $exp >expect($timeout ex $prompt) || die $exp >error();  print $exp set sqlprompt $prompt;n ;  $exp >expect($timeout ex $prompt) || die $exp >error();  $exp >clear_accum();    my $name = /tmp/sp_$ENV{USER} ;  unlink($name);  socket(S PF_UNIX SOCK_STREAM ) || 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/[rn]*$//g;    print $exp $cmd n ;    if ($cmd =~ /^exit$/mi)    {      print C exit n ;      close C;      last;    }    $exp >expect($timeout $prompt) || die $exp >error();    print C $exp >before();    close C;  }  $exp >soft_close();  close S;  unlink($name);  exit;    我把管道名叫做 sp_{username} 这样就允许同一个用户的两个不同会话共享同一个SQL*Plus会话 我使用默认的 SQL> 提示符 但是为了避免 SQL> 显示我的数据并导致数据被截断的可能性 最好还是使用一个长的随机字符串     下一步是Perl客户端     #!/usr/bin/perl w  # spc pl  use Socket;  use strict;  my $cmd = join( @ARGV);  my $name = /tmp/sp_$ENV{USER} ;  my $proto = getprotobyname( udp );  socket(S PF_UNIX SOCK_STREAM ) or die socket: $! ;  select S; $| = ; select STDOUT;  connect(S sockaddr_un($name)) or die connect: $! ;  print S $cmd n ;  print while (<S>);  close(S);  exit;     这段脚本连接到UDP服务器 发送一条单行命令(所有命令行参数的串联) 然后将数据发回标准输出 最后 如果服务进程还没有运行 两个Perl脚本的前面的CSH将启动服务程序然后将它们的参数传给客户端程序     #!/bin/csh  # sp csh  set f=/tmp/sp_$user  if ( e $f == ) then    perl spd pl &    sleep   endif  perl spc pl $*     现在 有了这个远程控制程序 我就可以像下面这样来做了     $ alias sp sp csh  $ sp connect scott/tiger   Connected   $ sp select * from dual;     D     X    $ sp select sysdate from dual; | grep MAY   MAY   $ sp select * from emp; | wc            $ sp exit     最后一条命令将关闭服务程序     这个提示中的脚本非常粗糙 不允许使用多行SQL语句 如果一个SQL语句不完整 服务进程将会挂起等待SQL提示符 如果SQL提示符改变服务进程也会挂起 但是在使用SQL*Plus的时候不丢掉shell环境依然非常有用 对于一般的命令使用它可以创建别名和使用shell功能 使用历史和替代变量 或者在内嵌环境中使用SQL*Plus lishixinzhi/Article/program/Oracle/201311/18504  
永远跟党走
  • 如果你觉得本站很棒,可以通过扫码支付打赏哦!

    • 微信收款码
    • 支付宝收款码