簡體   English   中英

將數組傳遞給Perl子例程

[英]Passing an array into Perl subroutine

我有一個子例程,該例程應將數組作為輸入,將其制成CSV,然后將其發布到URL。 到目前為止,這是我得到的:

一個示例數組:

[   2823383062, 1411691539,   1411691541,        'outgoing',
    'SIP/fr',   'user@2000',  '2000',            'SIP/2000-000000a2',
    undef,      '6125551234', 'SIP/fr-000000a3', undef,
    undef,      8,            'Answered',        2,
    1,          'nada'
];

子程序:

sub send_http {
    my @http = @_;
    my $h    = LWP::UserAgent->new;
    $h->timeout(15);
    $h->agent(undef);

    my $testkey = "1234";
    my $apikey  = "4567";

    my $posting;
    foreach my $v ( \@http ) {
        if ( defined $v ) {
            $posting = join( ',', $posting, $v );
        } else {
            $posting = join( ',', $posting, "" );
        }
    }

    my $api_response = $h->post( 'http://url.com/v1/post.cfm',
        [ key => $testkey, method => 'pushCalls', rawdata => $posting ] );
}

原諒我所做的所有可怕的事情; 這是我第一次使用Perl,但我仍在學習各種東西。 我的問題是,我似乎無法通過第一個數組變量聲明(@http)傳遞給它的數組中的值。 我讀過一些有關獲取數組引用的信息,但不確定在哪里/如何做。 任何幫助表示贊賞。

編輯:這是整個腳本。 它做(或應該)做兩件事; 將一些數據字符串發送到TCP套接字,而其他一些數據則通過POST發送到URL。 感謝大家的幫助。

#!/usr/bin/perl
use EV;
use Asterisk::AMI;
use Net::Telnet;
use HTTP::Request::Common;
use LWP::UserAgent;
use strict;
use warnings;
use Data::Dumper;

my %call;

my $t = new Net::Telnet (
  Timeout => 10,
  Port => '1234',
  Telnetmode => 1
);

my $astman = Asterisk::AMI->new(PeerAddr => '127.0.0.1',
  PeerPort => '5038',
  Username => 'secret',
  Secret => 'user',
  Events => 'on',
  Handlers => {  
#   default => \&eventhandler,
    Dial => \&dialcheck,
    Bridge => \&bridgecheck,
    Newchannel => \&newchannel,
    Newexten => \&newexten,
    Hangup => \&hangup,
    Newstate => \&outring
  }        
);

die "Unable to connect to asterisk" unless ($astman);

sub send_pos {
  my ($pos_string,$telnet) = @_;

  $telnet->open('127.0.0.1');
  printf $t $pos_string;
  $telnet->close()
}

sub send_http {
  my $http = shift; #@_;
  my $h = LWP::UserAgent->new;
    $h->timeout(15);
    $h->agent(undef);

  my $testkey = "1234";
  my $apikey = "5678";

  my $posting;
  foreach my $v ( @http ) {
    if ( defined $v ) {
      $posting = join(',', $posting,$v);
    } else {
      $posting = join(',', $posting,"");
    }
  }

  my $api_response = $h->post( 'http://url.com/v1/post.cfm',[key => $testkey,method => 'pushCalls',rawdata => $posting]);
}

sub eventhandler { 
  #   Default event handler, not used
  my ($ami, $event) = @_; 
  print 'Got Event: ',$event->{'Event'},"\r\n";
}

sub newchannel {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};

  if ( not exists $call{$unique_id} ) {
    my $this_call = $call{$unique_id};

  if ( (not defined $this_call->{'gravityfree'}[3]) ) {# || ($this_call->{'gravityfree'}[3] !~ /incoming|outgoing/) ) {
    if ( $event->{'Context'} =~ /from-trunk/ ) {
      #   Call is inbound
      $this_call->{'caller_name'} = $event->{'CallerIDName'};
      $this_call->{'caller_number'} = substr $event->{'CallerIDNum'}, -10;
      $this_call->{'dnis'} = substr $event->{'Exten'}, -10;
      $this_call->{'status'} = "remote";
      $this_call->{'holdstart'} = time();

      # Data required for Gravity Free
      $this_call->{'gravityfree'}[0] = int($event->{'Uniqueid'})+int(time());
      $this_call->{'gravityfree'}[3] = "incoming";
      $this_call->{'gravityfree'}[5] = $event->{'CallerIDName'};
      $this_call->{'gravityfree'}[6] = substr $event->{'CallerIDNum'}, -10;
      $this_call->{'gravityfree'}[7] =  $event->{'Channel'};
      $this_call->{'gravityfree'}[11] = substr $event->{'Exten'}, -10; 

      #  Can't remember why this is here:
      $call{$unique_id} = $this_call;

    } elsif ( $event->{'Context'} =~ /from-internal/ ) {
      #   Call is outbound
      #   Separate from calls to stations
      if( length($event->{'CallerIDNum'}) < length($event->{'Exten'}) ) {
          $this_call->{'status'} = "remote";
          #   Data required for Gravity Free
          $this_call->{'gravityfree'}[0] = int($event->{'Uniqueid'})+int(time());
          $this_call->{'gravityfree'}[9] = substr $event->{'Exten'}, -10;
          $this_call->{'gravityfree'}[3] = "outgoing";
          $this_call->{'gravityfree'}[6] = $event->{'CallerIDNum'};
          $this_call->{'gravityfree'}[5] = $event->{'CallerIDName'};

          $call{$unique_id} = $this_call;
      } elsif ( length($event->{'CallerIDNum'}) == length($event->{'Exten'}) ) {
        #   Call is station to station
        $this_call->{'status'} = "station-to-station";
      }
    }
  }
}
}

sub newexten {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};
  my $this_call = $call{$unique_id};

  #   Handles inbound calls only
  if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station
    #   Check if the DID has been defined
    if ( not defined $this_call->{'gravityfree'}[13] ) {
      if ( $event->{'Context'} eq 'ext-group' ) {
        # Data required for Gravity Free
        $this_call->{'gravityfree'}[13] = $event->{'Extension'};
      }
    }
  }
}

sub dialcheck {
  my ($ami, $event) = @_;
  my $unique_id = $event->{UniqueID};

  if ( exists $call{$unique_id} ) {
    my $this_call = $call{$unique_id};

    if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
      #   Call is not station to station
      if ( $event->{'SubEvent'} eq 'Begin' && $this_call->{'gravityfree'}[3] =~ "incoming" ) {
        #   Call is inbound
        $this_call->{'system_extension'} = $event->{'Dialstring'};
        $this_call->{'dest_uniqueid'}  = $event->{'DestUniqueID'};

        # Data required for Gravity Free
        $this_call->{'gravityfree'}[4] = $1 if $event->{'Channel'} =~ /(.+(?=\-\w+)).*/;

        #   Telnet data to Prodigy  
        my $sending = "R|$this_call->{'caller_name'}|$this_call->{'caller_number'}|$this_call->{'system_extension'}||$this_call->{'dnis'}|";
        send_pos($sending,$t);

        $this_call->{'status'}  = "ringing";
      } elsif ( $event->{SubEvent} eq 'Begin' && $this_call->{'gravityfree'}[3] =~ "outgoing" ) {
        #   Call is outbound
        #   Data required for Gravity Free
        $this_call->{'gravityfree'}[4] = $1 if $event->{'Destination'} =~ /(.+(?=\-\w+)).*/;
        $this_call->{'gravityfree'}[10] = $event->{'Destination'};
        $this_call->{'gravityfree'}[7] = $event->{'Channel'};
      }
    }
  }
}

sub outring {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};
  my $this_call = $call{$unique_id};

  if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station  
    if ( not defined $this_call->{'holdstart'} && $this_call->{'gravityfree'}[3] eq "outgoing" ) {
      #   Call is outbound
      $this_call->{'holdstart'} = time();
    }
  }
}

sub bridgecheck {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid1'};
  my $this_call = $call{$unique_id};

  if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station
    if ( $event->{'Bridgestate'} eq "Link" && length($event->{'CallerID2'}) <= 4 ) {
      #   Call is inbound
      $this_call->{'dest_uniqueid'}  = $event->{Uniqueid2};

      # Data required for Gravity Free
      $this_call->{'gravityfree'}[1] = time();
      $this_call->{'gravityfree'}[10] = $event->{Channel2};

      my $sending = "A|$this_call->{caller_name}|$this_call->{caller_number}|$event->{CallerID2}||$this_call->{dnis}|";
      send_pos($sending,$t);

      $this_call->{'status'}  = "answered";

    } elsif ( $event->{'Bridgestate'} eq "Link" && length($event->{'CallerID2'}) >= 4 ) {
      #   Call is outbound
        $this_call->{'gravityfree'}[1] = time();
        $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[1]-$this_call->{holdstart};
    }
  }
}


sub hangup {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};
  my $this_call = $call{$unique_id};

  if ( defined $this_call->{'status'} && not defined $this_call->{'gravityfree'}[16] && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station
    if ( $event->{'Cause-txt'} eq "Normal Clearing" ) {
      #   Call was hungup normally
      $this_call->{'dest_uniqueid'}  = $event->{Uniqueid};
      #   Call has ended, get date/time
      $this_call->{'gravityfree'}[2] = time();
      #   Mark call 'completed'
      $this_call->{'gravityfree'}[16] = 1;
      #   Set notes to nothing
      $this_call->{'gravityfree'}[17] = 'nada';

      if ( defined $this_call->{'gravityfree'}[3] && $this_call->{'gravityfree'}[3] eq "incoming") {
        #   Call was inbound
        if ( defined $this_call->{'gravityfree'}[1] ) {
          #   Call was answered
          $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[1]-$this_call->{holdstart};
          $this_call->{'gravityfree'}[14] = "Answered";
          $this_call->{'gravityfree'}[15] = $this_call->{'gravityfree'}[2]-$this_call->{'gravityfree'}[1];
          $this_call->{'gravityfree'}[8] = $event->{'ConnectedLineName'};
          $this_call->{'gravityfree'}[9] = substr $event->{'ConnectedLineNum'}, -10;

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});

        } else {
          #   Call was abandoned
          $this_call->{'gravityfree'}[14] = "Abandoned";
          $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[2]-$this_call->{holdstart};
          $this_call->{'gravityfree'}[15] = 0;

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});
        }

      } elsif ( defined $this_call->{'gravityfree'}[3] && $this_call->{'gravityfree'}[3] eq "outgoing" ) {
        #   Call is outbound
        if ( defined $this_call->{'gravityfree'}[1] ) {
          #   Call was bridged at some point
          $this_call->{'gravityfree'}[15] = $this_call->{'gravityfree'}[2]-$this_call->{'gravityfree'}[1];
          $this_call->{'gravityfree'}[14] = "Answered";

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});
        } else {
          #   Call was hung up before anyone answered
          $this_call->{'gravityfree'}[15] = 0;
          $this_call->{'gravityfree'}[14] = "Abandoned";
          $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[2]-$this_call->{holdstart};

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});
        }
      }
    }
  }
}

EV::loop

第一個問題,您將從何處獲得要傳遞給子例程的數組? 我問是因為您的示例數組實際上是數組引用。

那是:

@array = (1, 2, 3);  # This is an array
$ref   = [1, 2, 3];  # This is an array reference

如果要將數組引用傳遞給子例程,請將開始位置更改為:

sub send_http {
my $http = shift;

接下來,讓我們考慮如何遍歷數組的元素。 這是這樣做的正確方法:

foreach my $element ( @array ) { 
  # do stuff ...
}

在數組上執行\\ @時,實際上是在創建對該數組的引用。 因此,如果您確實要將數組傳遞給子例程,則應將循環更改為以下內容:

foreach my $v ( @http ) {

但是,如果您決定將數組作為引用傳遞,則可以取消引用指針並遍歷其元素,如下所示:

foreach my $v ( @$http ) {

希望這可以幫助!

編輯:對於新上載的代碼...

您的關系非常密切,但是我們有幾個小問題:

$ this_call-> {'gravityfree'}實際上已經是數組引用,我不確定為什么它允許您使用$ this_call-> {'gravityfree'} [INDEX]處理數組元素,所以也許有人比我可以啟發我們所有人。 我將注意到,引用數組的正確方法如下:

\@{$this_call->{'gravityfree'}}

無論如何,您只需將引用傳遞給子例程,而無需創建引用。 那是:

send_http($this_call->{'gravityfree'});

現在,在子例程中,您有了數組引用。 您正在正確讀取子例程參數,但是您需要在foreach循環中取消引用該引用。 像這樣:

foreach my $v ( @$http ) {
  # ... loop body
}

這有意義嗎? 如果有任何不清楚的地方(或不起作用!),請通知我。

因此,在send_http中,您收到的參數是array_ref,它是標量變量,因此在使用它時,需要取消對正確類型的引用。

注意:方括號是array_reference

因此,請進行如下更改:

my $http = shift;

並將其用作:

foreach my $v ( @$http ) {

例:

my $array_ref = [1,2,3];
print "Reference: ", $array_ref,"\n";
print "Array: ", @$array_ref,"\n";

輸出:

Reference: ARRAY(0x7f8e1c004ee8)
Array: 123

我不確定您要做什么,但一切都取決於您如何將數組傳遞給子例程。 您有兩種選擇,可以將其作為數組傳遞:

send_http(@array)

或作為對數組的引用:

send_http(\@array)

正如其他人指出的那樣,由於您在方括號[ ]定義了數組,因此它已經是一個引用。

您想要哪一個取決於您到底在做什么,但是語法不同。 傳遞數組並遍歷它:

sub send_http {
my @http = @_;
  foreach my $v (@http) {
      print "v is $v\n";
 }
}
my @aa=("cc","dd");
send_http(@aa);

要傳遞引用並遍歷數組,它指向:

sub send_http {
 ## Remove the first value from the @_ array.
 my $http = shift @_;
 ## Dereference it to an array. You could also use @{$http}
 foreach my $v (@$http) {
      print "v is $v\n";
 }
}

my @aa=("cc","dd");
send_http(\@aa);

主要區別在於,當您使用send_http(\\@aa); 您傳遞的不是數組,因此您不能將其視為一個數組。 相反,它是對數組的引用。 就像是

send_http(ARRAY(0x1d34030));

因此,內容@_只是一個參考, ARRAY(0x1d34030) 要將其視為數組,您需要取消引用它才能指向它所指向的內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM