国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

使用Expect和命名管狀遠(yuǎn)程控制SQL*Plus

2024-07-21 02:34:43
字體:
供稿:網(wǎng)友

  在初始化一個(gè)SQL*Plus會(huì)話的時(shí)候,對(duì)shell的訪問會(huì)受到HOST命令和運(yùn)行存儲(chǔ)的SQL*Plus腳本的限制。SQL*Plus不具有別名(alias)或者歷史等特性,也不具備把一個(gè)命令的輸出通過管道傳入別的命令的能力。 假如能將SQL*Plus的特性添加到現(xiàn)有的shell環(huán)境中豈不是一件美事?這里正好有一種方法可以實(shí)現(xiàn)這一想法。
  
  在UNIX中,創(chuàng)建一個(gè)守護(hù)進(jìn)程來將命令從獨(dú)立的shell命令傳入一個(gè)SQL*Plus會(huì)話是可能實(shí)現(xiàn)的。第一步是創(chuàng)建一樣能與SQL*Plus交互環(huán)境進(jìn)行交互的東西。雖然SQL*Plus是可交互的,但是它僅限于STDOUT和STDIN,所以它可以放入一個(gè)管道中:
  
  sqlplus /nolog < commands.sql > output.log
  
  然而,假如我們想一次發(fā)出一條SQL*Plus命令,那么就需要檢查SQL*Plus命令提示符“SQL>”來判定SQL*Plus是否在等待輸入,然后使用非阻塞管道,這樣我們可以在碰到提示符時(shí)停止讀取數(shù)據(jù)而等待SQL*Plus更多的輸入。
  
  一種天生可以完成這項(xiàng)工作的腳本描述語言是EXPect,它是Tcl/Tk程序設(shè)計(jì)語言的衍生物。這個(gè)進(jìn)程可以是守護(hù)進(jìn)程或者是服務(wù)進(jìn)程,它接收單個(gè)的遠(yuǎn)程控制命令并將它們傳遞給從屬SQL*Plus會(huì)話。要與這個(gè)服務(wù)進(jìn)程通信,用法最簡(jiǎn)單的協(xié)議是UNIX Domain PRotocol(UDP) sockets。shell可以通過UDP客戶端發(fā)出命令,然后命令由服務(wù)進(jìn)程接收,然后其結(jié)果就通過socket發(fā)回到客戶端。
  
  Expect需要一個(gè)擴(kuò)展才能夠使用UDP sockets。與其安裝該擴(kuò)展到Expect,不如在Perl中使用Expect,因?yàn)镻erl已經(jīng)能夠很好地處理sockets。在Perl歸檔中可以找到Expect.pm。這個(gè)程序提供在Perl中使用Expect相同的功能。
  
  下面是我的簡(jiǎn)單示例服務(wù)程序,使用Perl、UDP和Expect.pm作為我的行程控制服務(wù)程序:
  
  #!/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;/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,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/[/r/n]*$//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}”。這樣就答應(yīng)同一個(gè)用戶的兩個(gè)不同會(huì)話共享同一個(gè)SQL*Plus會(huì)話。我使用默認(rèn)的“SQL>”提示符,但是為了避免“SQL>”顯示我的數(shù)據(jù)并導(dǎo)致數(shù)據(jù)被截?cái)嗟目赡苄裕詈眠€是使用一個(gè)長(zhǎng)的隨機(jī)字符串。
  
  下一步是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,0) or die "socket: $!";
  select S; $ = 1; select STDOUT;
  connect(S,sockaddr_un($name)) or die "connect: $!";
  print S $cmd,"/n";
  print while (<S>);
  close(S);
  exit;
  
  這段腳本連接到UDP服務(wù)器,發(fā)送一條單行命令(所有命令行參數(shù)的串聯(lián)),然后將數(shù)據(jù)發(fā)回標(biāo)準(zhǔn)輸出。
最后,假如服務(wù)進(jìn)程還沒有運(yùn)行,兩個(gè)Perl腳本的前面的CSH將啟動(dòng)服務(wù)程序然后將它們的參數(shù)傳給客戶端程序:
  
  #!/bin/csh
  # sp.csh
  set f=/tmp/sp_$user
  if (-e $f == 0) then
    perl spd.pl &
    sleep 1
  endif
  perl spc.pl "$*"
  
  現(xiàn)在,有了這個(gè)遠(yuǎn)程控制程序,我就可以像下面這樣來做了:
  
  $ alias sp sp.csh
  $ sp "connect scott/tiger"
  Connected.
  $ sp "select * from dual;"
  
  D
  -
  X
  
  $ sp "select sysdate from dual;" grep MAY
  05-MAY-03
  $ sp "select * from emp;" wc
    70  184  1890
  $ sp "exit"
  
  最后一條命令將關(guān)閉服務(wù)程序。
  
  這個(gè)提示中的腳本非常粗糙;不答應(yīng)使用多行SQL語句。假如一個(gè)SQL語句不完整,服務(wù)進(jìn)程將會(huì)掛起等待SQL提示符;假如SQL提示符改變服務(wù)進(jìn)程也會(huì)掛起。但是在使用SQL*Plus的時(shí)候不丟掉shell環(huán)境依然非常有用。對(duì)于一般的命令使用它可以創(chuàng)建別名和使用shell功能,使用歷史和替代變量,或者在內(nèi)嵌環(huán)境中使用SQL*Plus。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 瑞安市| 凤凰县| 长丰县| 寿阳县| 平潭县| 饶平县| 琼海市| 图们市| 衡水市| 怀集县| 和平区| 舒城县| 汕尾市| 墨脱县| 香河县| 肃南| 肃南| 湘潭县| 武平县| 虎林市| 墨玉县| 沾益县| 广昌县| 将乐县| 措勤县| 仙居县| 韩城市| 深水埗区| 秀山| 嘉兴市| 海伦市| 祁门县| 兴海县| 托克逊县| 台安县| 赣榆县| 屏东市| 平阴县| 土默特左旗| 巴中市| 太和县|