파라미터 패싱에 대한 좋은 펄 코드가 있어서 소개한다.

 

 

출처 :

 

http://www.cs.cf.ac.uk/Dave/PERL/node61.html

Passing Parameters to Functions

When we introduced Functions we talked about passing parameters to functions. At the time, we were not able to pass more than one array to a function. This was because functions only see one array (the @_ array) when looking for parameters. References can be used to overcome this limitation.

Let's start off by passing two arrays into a function to show that the function only sees one array (pass_par.pl):

firstSub( (1..5), ("A".."E"));



sub firstSub {

    my(@firstArray, @secondArray) = @_ ;



    print("The first array is  @firstArray.\n");

    print("The second array is @secondArray.\n");

}

This program displays:

The first array is  1 2 3 4 5 A B C D E.

The second array is .

Inside the firstSub() function, the @firstArray variable was assigned the entire parameter array, leaving nothing for the @secondArray variable. By passing references to @arrayOne and @arrayTwo, we can preserve the arrays for use inside the function. Very few changes are needed to enable the above example to use references (pass_ref.pl):

@array1  = (1..5);
@array2  = ("A".."E");

firstSub( \@array1,  \@array2);         # One



sub firstSub {

    my($ref_firstArray, $ref_secondArray) = @_;   # Two



    print("The first array is  @{$ref_firstArray}.\n");  # Three

    print("The second array is @{$ref_secondArray}.\n"); # Three

}

This program displays:

The first array is  1 2 3 4 5.

The second array is A B C D E.

Three things were done to make this example use references:

1.
In the line marked "One," backslashes were added to indicate that a reference to the array should be passed.
2.
In the line marked "Two," the references were taken from the parameter array and assigned to scalar variables.
3.
In the lines marked "Three," the scalar values were dereferenced. Dereferencing means that Perl will use the reference as if it were a normal data type-in this case, an array variable.

An alternative more modern way of achieving the same as above is to create a Perl Reference array using square brackets:

firstSub( [1..5], ["A".."E"] );


sub firstSub {

    my($ref_firstArray, $ref_secondArray) = @_;    # Two



    print("The first array is  @{$ref_firstArray}.\n");  # Three

    print("The second array is @{$ref_secondArray}.\n"); # Three

}

'perl' 카테고리의 다른 글

Array 다루기 #2  (0) 2008.06.05
Array 다루기 #1  (0) 2008.06.05
Perl의 String 관련 함수  (0) 2008.03.22
bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
Posted by '김용환'
,

Perl의 String 관련 함수

perl 2008. 3. 22. 02:59

 

 

출처 : http://www.perlmeme.org/howtos/perlfunc/

 

 

Using the Perl chomp() function

Introduction

The chomp() function will remove (usually) any newline character from the end of a string. The reason we say usually is that it actually removes any character that matches the current value of $/ (the input record separator), and $/ defaults to a newline.

For more information on the $/ variable, try perldoc perlvar and see the entry for $/.

Example 1. Chomping a string

Most often you will use chomp() when reading data from a file or from a user. When reading user input from the standard input stream (STDIN) for instance, you get a newline character with each line of data. chomp() is really useful in this case because you do not need to write a regular expression and you do not need to worry about it removing needed characters.

When running the example below, using the enter key on a line by itself will exit the program.

  #!/usr/bin/perl
  use strict;
  use warnings;

  while (my $text = <STDIN>) {
    chomp($text);
    print "You entered '$text'\n";
    last if ($text eq '');
  }

Example usage and output of this program is:

  a word
  You entered 'a word'
  some text
  You entered 'some text'

  You entered ''

Example 2. Chomping an array

If you chomp an array, it will remove a newline from the end of every element in the array:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my @array = ("bob\n", "jill", "fred\n");

  print "Before chomp:\n";
  print "@array\n";

  chomp(@array);

  print "After chomp:\n";
  print "@array\n";

This program produces the following output:

  Before chomp:
  bob
   jill fred

  After chomp:
  bob jill fred

As you can see, the newlines have been removed from "bob" and "fred", but no characters have been removed from "jill".

Example 3. Chomping a hash

If you pass a hash into chomp(), it will remove newlines from every value (not key) of the hash:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my %hash = (
    'first' => "one\n",
    'second' => "two\n",
    'third' => "three\n",
  );

  chomp(%hash);

  foreach my $k (keys %hash) {
    print "$k: $hash{$k} ";
  }

  print "\n";

  exit 0;

This program outputs:

  first: one second: two third: three

See also

 

 

 

 

 

Using the Perl chop() function

Introduction

Sometimes you will find you want to unconditionally remove the last character from a string. While you can easily do this with regular expressions, chop is more efficient.

The chop() function will remove the last character of a string (or group of strings) regardless of what that character is. Note, if you want to easily remove newlines or line separators see the chomp() howto.

Example 1. Chopping a string

The chop() function removes and returns the last character from the given string:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'frog';

  my $chr = chop($string);

  print "String: $string\n";
  print "Char: $chr\n";

This program gives you:

  String: fro
  Char: g

If the string is empty, chop() will return an empty string. If the string is undefined, chop() will return undefined.

Example 2. Chopping strings in an array

If you pass the chop() function an array, it will remove the last character from every element in the array.

Note that this will only work for a one-dimensional array. In other words, it is not valid to pass in an array reference, or an array that contains an array (or hash).

  #!/usr/bin/perl
  use strict;
  use warnings;

  my @array = ('fred', 'bob', 'jill', 'joan');

  my $chr = chop(@array);

  foreach my $str (@array) {
    print "$str\n";
  }

  print "Char: $chr\n";

This produces the output:

  fre
  bo
  jil
  joa
  Char: n

Example 3. Chopping strings in a hash

If you pass a hash into chop(), it will remove the last character from the values (not the keys) in the hash. For example:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my %hash = (
    first => 'one',
    second => 'two',
    third => 'three',
  );

  my $chr = chop(%hash);

  foreach my $k (keys %hash) {
    print "$k: $hash{$k}\n";
  }

  print "Char: $chr\n";

This program outputs:

  first: on
  second: tw
  third: thre
  Char: e

Note that as with arrays, chop is not designed to process hash reference or hashes containing other hashes (or arrays).

 

 

 

 

Introduction

The index() function is used to determine the position of a letter or a substring in a string. For example, in the word "frog" the letter "f" is in position 0, the "r" in position 1, the "o" in 2 and the "g" in 3. The substring "ro" is in position 1. Depending on what you are trying to achieve, the index() function may be faster or more easy to understand than using a regular expression or the split() function.

Example 1a. Where in a string is a certain letter?

Let's say you are trying to determine if a word has a particular letter in it. Let's look for the letter "l" in the string "perlmeme.org".

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'l';

  my $result = index($string, $char);

  print "Result: $result\n";

This program gives you:

  Result: 3

Example 1b. The string doesn't contain the letter?

If the string doesn't contain the letter, index() will return a -1. For example, we can look for the letter "L" in the string "perlmeme.org":

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'L';

  my $result = index($string, $char);

  print "Result: $result\n";

The program outputs:

  Result: -1

Example 1c. The string contains more than one of the letter?

If the letter we're searching for appears more than once in the string, index() return the index of the first occurrence of the letter.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';

  my $result = index($string, $char);

  print "Result: $result\n";

This program gives you:

  Result: 1

Example 2. Looking for a substring

Looking for a substring (rather than a single character) works in exactly the same way as looking for a single character:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $substr = 'me';

  my $result = index($string, $substr);

  print "Result: $result\n";

This program gives you:

  Result: 4

Example 3a. What if I don't want the first occurrence?

The index() function let's you specify an offset. This tells index() where to start looking in the string. In our example, we found the first occurrence of the letter 'e' at position 1. Let's try to find the second:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';

  # The first 'e' was at position 1, so let's start 
  # looking again at position 2
  my $offset = 2;

  my $result = index($string, $char, $offset);

  print "Result: $result\n";

The program outputs:

  Result: 5

Example 3b. How to find every occurrence

To find (and do something with) every occurrence of a character in a string, you could use index() in a loop, incrementing the offset each time:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';
  my $offset = 0;

  my $result = index($string, $char, $offset);

  while ($result != -1) {

    print "Found $char at $result\n";

    $offset = $result + 1;
    $result = index($string, $char, $offset);

  }

When we run this program, we get the following output:

  Found e at 1
  Found e at 5
  Found e at 7

Example 4. How to find the last occurrence

Instead of looping through every occurrence of a letter in a string to find the last one, you can use the rindex() function. This works exactly the same as index() but it starts at the end of the string. The index value returned is string from the start of the string though.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';

  my $result = rindex($string, $char);

  print "Result: $result\n";

This would produce:

  Result: 7

For more information on rindex() see our rindex() howto.

 

 

 

Using the Perl push() function

Introduction

You can use the push function to add new elements to the end of an array.

Example 1. Adding an item onto an array

You can use push to push an element onto the end of an array:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @planets = qw(mercury venus earth mars);

    print "@planets\n";

    push (@planets, 'jupiter');

    print "@planets\n";

    exit 0;

This program produces the following output:

    mercury venus earth mars
    mercury venus earth mars jupiter

You can see that 'jupiter' is now on the end of our @planets array.

The push function returns the number of elements in the array after the new value(s) have been appended. If we wanted to see how many planets were in the modified @planets array, we could change our code as follows:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @planets = qw(mercury venus earth mars);

    print "@planets\n";

    my $number_of_planets = push (@planets, 'jupiter');

    print "@planets\n";

    print "The number of planets is: $number_of_planets\n";

    exit 0;

The output is now:

    mercury venus earth mars
    mercury venus earth mars jupiter
    The number of planets is: 5

Example 2. Joining two arrays together

You can also use push to append an array onto the end of another array:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @planets = qw(mercury venus earth mars);

    my @outer_planets = qw(jupiter saturn uranus neptune pluto);

    print "@planets\n";

    push (@planets, @outer_planets);

    print "@planets\n";

    exit 0;

As the following output demonstrates, the @outer_planets array has been added to the end of the @planets array:

    mercury venus earth mars
    mercury venus earth mars jupiter saturn uranus neptune pluto

Example 3. Adding to an array reference

You can use push to append elements onto the end of a reference to an array, but you must dereference it first:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @planets = qw(mercury venus earth mars);

    my $planets_ref = \@planets;

    push ( @{ $planets_ref }, qw(jupiter saturn uranus neptune pluto));

    # Could also be written as:
    # push ( @$planets_ref, qw(jupiter saturn uranus neptune pluto));

    print "@{ $planets_ref }\n";

    # Could also be written as:
    # print "@$planets_ref\n";

    exit 0;

This produces the following output:

    mercury venus earth mars jupiter saturn uranus neptune pluto
 

Using the Perl qw() function

Introduction

The 'quote word' function qw() is used to generate a list of words. If takes a string such as:

    tempfile tempdir

and returns a quoted list:

    'tempfile', 'tempdir'

saving you from the tedium of having to quote and comma-separate each element of the list by hand. Here's a full example:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use File::Temp qw(tempfile tempdir);

This code fragment has the effect of importing the tempfile and tempdir functions from the File::Temp module. It does this by providing the list 'tempfile', 'tempdir' to the use function.

How it works

qw() extracts words out of your string using embedded whitsepace as the delimiter and returns the words as a list. Note that this happens at compile time, which means that the call to qw() is replaced with the list before your code starts executing.

Convenience

The qw() function is one of the many ways in which Perl helps to make it easier to write code. Wherever you need to construct a list like this:

    my @names = ('Kernighan', 'Ritchie', 'Pike');

you can use qw to do the same thing more simply:

    my @names = qw(Kernighan Ritchie Pike);

Delimeters

You can use any non-alphanumeric, non-whitespace delimeter to surround the qw() string argument. You'll often see qw//, for example.

If you use any of the bracketing characters (, <, [ or { as your delimeter, you'll have to close with a matching bracket.

So the following are equivalent:

    @names = qw(Kernighan Ritchie Pike);
    @names = qw/Kernighan Ritchie Pike/;
    @names = qw'Kernighan Ritchie Pike';
    @names = qw{Kernighan Ritchie Pike};

Additionlly, no interpolation is possible in the string you pass to qw().

This code fragment:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my $developer = 'Thompson';
    my @names = qw(Kernighan Ritchie Pike $developer);
    foreach my $name (@names) {
        print "name: $name\n";
    }

Will output:

    name: Kernighan
    name: Ritchie
    name: Pike
    name: $developer

Quotes as operators

In Perl, quotes are considered operators. We have dealt with qw() here as if it was a function, (and indeed it is listed as such in the standard perlfunc documentation), but this is not the whole story. In order to get a better picture of the subtlety of Perl's quoting, see the following section in the perlop documentation:

    Quote and Quote-like Operators
    Regexp Quote-Like Operators
 
 
 

Using the Perl rand() function

Introduction

The rand() function is used to generate random numbers. By default it generates a number between 0 and 1, however you can pass it a maximum and it will generate numbers between 0 and that number.

Example 1. Between 0 and 1

To generate a random decimal number between 0 and 1, use rand() without any parameters.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $random_number = rand();

  print $random_number . "\n";

This will give you a random number, like:

  0.521563085335405

Example 2. A bigger range of numbers

Quite often you don't want a number between 0 and 1, but you want a bigger range of numbers. If you pass rand() a maximum, it will return a decimal number between 0 and that number. Our example below generates a random number between 0 and 100.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $range = 100;

  my $random_number = rand($range);

  print $random_number . "\n";

The program will produce something like:

  34.0500569277541

Example 3. A random integer

To generate a random integer, convert the output from rand to an integer, as follows:

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $range = 100;

  my $random_number = int(rand($range));

  print $random_number . "\n";

This program gives you an integer from 0 to 99 inclusive:

  68

Example 4. With an offset

To generate a random number between, for example, 100 and 150, simply work out the range and add the minimum value to your random number.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $range = 50;
  my $minimum = 100;

  my $random_number = int(rand($range)) + $minimum;

  print $random_number . "\n";

This program gives you:

  129
 
 

Using the Perl rindex() function

Introduction

The rindex() function is used to determine the position of a character in a string starting at the end of the string. We recommend that you first read our index() howto.

rindex() works exactly the same as index() except that it returns the index of the last occurrence of a letter or substring in the string.

Example 1a. Finding the last occurrence of a letter in a string.

We want to find the last occurrence of the letter "m" in the string "perlmeme.org".

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'm';

  my $result = rindex($string, $char);

  print "Result: $result\n";

This program gives you:

  Result: 6

Example 1b. The string doesn't contain the letter?

Just like for index() if the string doesn't contain the letter, rindex() will return a -1. For example, we can look for the letter "L" in the string "perlmeme.org":

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'L';

  my $result = rindex($string, $char);

  print "Result: $result\n";

The program outputs:

  Result: -1

Example 2a. The string contains more than one of the letter?

If the letter we're searching for appears more than once in the string, rindex() return the index of the first occurrence of the letter.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';

  my $result = rindex($string, $char);

  print "Result: $result\n";

This program gives you:

  Result: 7

Example 2b. What if I want the second last occurrence?

The offset parameter for rindex() works slightly differently to the offset parameter for index().

In index() the character of substring will be searched for starting at the offset position. For example, the first occurrence of the letter 'e' in the string "perlmeme.org" is at position 1. If we want to find the second occurrence, we set the offset to 2.

With rindex() we start at the offset position and look backwards. The last occurrence of the letter 'e' is at position 7. So to find the second last occurrence we set the offset to 6.

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';

  # The first 'e' was at position 1, so let's start 
  # looking again at position 2
  my $offset = 6;

  my $result = rindex($string, $char, $offset);

  print "Result: $result\n";

The program outputs:

  Result: 5

Example 2c. How to find every occurrence

To find (and do something with) every occurrence of a character in a string using rindex(), you could use index() in a loop, decrementing the offset each time. Note that when using an offset, we need to tell rindex() to start at the back of the string (otherwise it starts at 0 which returns no results).

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'perlmeme.org';
  my $char = 'e';
  # Start at the end of the string
  my $offset = length($string);

  my $result = rindex($string, $char, $offset);

  while ($result != -1) {

    print "Found $char at $result\n";

    $offset = $result - 1;
    $result = rindex($string, $char, $offset);

  }

When we run this program, we get the following output:

  Found e at 7
  Found e at 5
  Found e at 1
 
 

Sorting

The sort function sorts a list (an array). The default is to sort alphabetically. However, you can define your own sorts to get around numbers and complex data structures.

Sort an array of strings

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @strings = ("Becky", "Simon", "Bianca", "Steven", "Greg", "Andrew");

    my @sorted_strings = sort @strings;
    print "@sorted_strings\n";

This gives you the following output:

    Andrew Becky Bianca Greg Simon Steven

Sort an array of numbers

The Perl sort function sorts by strings instead of by numbers. If you were to use:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @numbers = (23, 1, 22, 7, 109, 9, 65, 3);

    my @sorted_numbers = sort @numbers;
    print "@sorted_numbers\n";

The output you would see would be:

    1 109 22 23 3 65 7 9

To sort numerically, declare your own sort block and use the flying saucer operator <=>:

    #!/usr/bin/perl
    use strict;
    use warnings;

    my @numbers = (23, 1, 22, 7, 109, 9, 65, 3);

    my @sorted_numbers = sort {$a <=> $b} @numbers;
    print "@sorted_numbers\n";

The output would now be:

    1 3 7 9 22 23 65 109

Note that $a and $b do not need to be declared, even with use strict on, because they are special sorting variables.

To find out more, see the tutorial Sorting in perl, or run the command:

    perldoc -f sort
 
 

Using the Perl split() function

Introduction

The split() function is used to split a string into smaller sections. You can split a string on a single character, a group of characers or a regular expression (a pattern).

You can also specify how many pieces to split the string into. This is better explained in the examples below.

Example 1. Splitting on a character

A common use of split() is when parsing data from a file or from another program. In this example, we will split the string on the comma ','. Note that you typically should not use split() to parse CSV (comma separated value) files in case there are commas in your data: use Text::CSV instead.

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'Becky Alcorn,25,female,Melbourne';

  my @values = split(',', $data);

  foreach my $val (@values) {
    print "$val\n";
  }

  exit 0;

This program produces the following output:

  Becky Alcorn
  25
  female
  Melbourne

Example 2. Splitting on a string

In the same way you use a character to split, you can use a string. In this example, the data is separated by three tildas '~~~'.

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'Bob the Builder~~~10:30am~~~1,6~~~ABC';

  my @values = split('~~~', $data);

  foreach my $val (@values) {
    print "$val\n";
  }

  exit 0;

This outputs:

  Bob the Builder
  10:30am
  1,6
  ABC

Example 3. Splitting on a pattern

In some cases, you may want to split the string on a pattern (regular expression) or a type of character. We'll assume here that you know a little about regular expressions. In this example we will split on any integer:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'Home1Work2Cafe3Work4Home';

  # \d+ matches one or more integer numbers
  my @values = split(/\d+/, $data);

  foreach my $val (@values) {
    print "$val\n";
  }

  exit 0;

The output of this program is:

  Home
  Work
  Cafe
  Work
  Home

Example 4. Splitting on an undefined value

If you split on an undefined value, the string will be split on every character:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'Becky Alcorn';

  my @values = split(undef,$data);

  foreach my $val (@values) {
    print "$val\n";
  }

  exit 0;

The results of this program are:

  B
  e
  c
  k
  y

  A
  l
  c
  o
  r
  n

Example 5. Splitting on a space

If you use a space ' ' to split on, it will actually split on any kind of space including newlines and tabs (regular expression /\s+/) rather than just a space. In this example we print 'aa' either side of the values so we can see where the split took place:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = "Becky\n\nAlcorn";

  my @values = split(' ',$data);

  # Print 'aa' either side of the value, so we can see where it split
  foreach my $val (@values) {
    print "aa${val}aa\n";
  }

  exit 0;

This produces:

  aaBeckyaa
  aaAlcornaa

As you can see, it has split on the newlines that were in our data. If you really want to split on a space, use regular expressions:

  my @values = split(/ /,$data);

Example 6. Delimiter at the start of the string

If the delimiter is at the start of the string then the first element in the array of results will be empty. We'll print fixed text with each line so that you can see the blank one:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = ',test,data';

  my @values = split(',',$data);

  # We print "Val: " with each line so that you can see the blank one
  foreach my $val (@values) {
    print "Val: $val\n";
  }

  exit 0;

The output of this program is:

  Val: 
  Val: test
  Val: data

Example 7. Split and context

If you do not pass in a string to split, then split() will use $_. If you do not pass an expression or string to split on, then split() will use ' ':

  #!/usr/bin/perl

  use strict;
  use warnings;

  foreach ('Bob the Builder', 'Thomas the TankEngine', 'B1 and B2') {
    my @values = split;
    print "Split $_:\n";
    foreach my $val (@values) {
      print "  $val\n";
    }
  }

  exit 0;

This produces:

  Split Bob the Builder:
    Bob
    the
    Builder
  Split Thomas the TankEngine:
    Thomas
    the
    TankEngine
  Split B1 and B2:
    B1
    and
    B2

Example 8. Limiting the split

You can limit the number of sections the string will be split into. You can do this by passing in a positive integer as the third argument. In this example, we're splitting our data into 3 fields - even though there are 4 occurrances of the delimiter:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'Becky Alcorn,25,female,Melbourne';

  my @values = split(',', $data, 3);

  foreach my $val (@values) {
    print "$val\n";
  }

  exit 0;

This program produces:

  Becky Alcorn
  25
  female,Melbourne

Example 9. Keeping the delimiter

Sometimes, when splitting on a pattern, you want the delimiter in the result of the split. You can do this by capturing the characters you want to keep inside parenthesis. Let's do our regular expression example again, but this time we'll keep the numbers in the result:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'Home1Work2Cafe3Work4Home';

  # \d+ matches one or more integer numbers
  # The parenthesis () mean we keep the digits we match
  my @values = split(/(\d+)/, $data);

  foreach my $val (@values) {
    print "$val\n";
  }

  exit 0;

The output is:

  Home
  1
  Work
  2
  Cafe
  3
  Work
  4
  Home

Example 10. Splitting into a hash

If you know a bit about your data, you could split it directly into a hash instead of an array:

  #!/usr/bin/perl

  use strict;
  use warnings;

  my $data = 'FIRSTFIELD=1;SECONDFIELD=2;THIRDFIELD=3';

  my %values =  split(/[=;]/, $data);

  foreach my $k (keys %values) {
    print "$k: $values{$k}\n";
  }

  exit 0;

The output of this program is:

  FIRSTFIELD: 1
  THIRDFIELD: 3
  SECONDFIELD: 2

The problem is that if the data does not contain exactly what you think, for example FIRSTFIELD=1;SECONDFIELD=2;THIRDFIELD= then you will get an 'Odd number of elements in hash assignment' warning. Here is the output of the same program but with this new data:

 

 

Using the Perl substr() function

Introduction

The substr() function is used to return a substring from the expression supplied as it's first argument. The function is a good illustration of some of the ways in which Perl is different from other languages you may have used. substr() has a variable number of arguments, it can be told to start at an offset from either end of the expression, you can supply a replacement string so that it replaces part of the expression as well as returning it, and it can be assigned to!

Example 1a. Supply an expression and a positive offset value.

In our first example, we'll use $string as the first argument, or expression, and supply the offset argument to indicate how far from the left side of the expression our substring should start. Since substr() returns the substring that it matches, we assign this value to $fragment

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $fragment =  substr $string, 4;
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

This script produces the following output:

    string: <Now is the time for all good people to come to the aid of their party>
  fragment: <is the time for all good people to come to the aid of their party>

In $string, the 'i' in the word 'is' is at offset four, because the function starts counting at zero. Therefore the letter 'N' is at offset 0, 'o' is at offset 1, 'w' is at offset 2, and so on.

Example 1b. Supply an expression and a positive offset value.

If we increase the offset to 7, the substring return by substr() starts at the word 'the'.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $fragment =  substr $string, 7;
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

    string: <Now is the time for all good people to come to the aid of their party>
  fragment: <the time for all good people to come to the aid of their party>

Example 1c. Supply an expression and a positive offset value.

In this example, instead of an explicit offset argument, we'll use the index() function to determine the position of the word 'people'.

  #!/usr/bin/perl
  use strict;
  use warnings;

  # Find the location of the substring 'people'

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $fragment =  substr $string, index($string, 'people');
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

    string: <Now is the time for all good people to come to the aid of their party>
  fragment: <people to come to the aid of their party>

Example 2a. Supply an expression, a positive offset value and a length

We can supply a third argument to substr(), to limit the size of the substring that is returned. This is the length argument.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $length = 8;
  my $fragment =  substr $string, 7, $length;
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

Now we're starting at offset 7 and only returning $length bytes.

    string: <Now is the time for all good people to come to the aid of their party>
  fragment: <the time>

Example 2b. Supply an expression, a negative offset value and a length

If we supply a negative offset value, then substr() starts that many characters from the end of the string. Here our offset is -16. which means that our substring will start at the word 'aid', and since our length argument is 10, the function returns the string 'd of their'.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $length = 10;
  my $fragment =  substr $string, -16, $length;
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

    string: <Now is the time for all good people to come to the aid of their party>
  fragment: <d of their>

Example 2c. Supply an expression, a positive offset value and a negative length

If we supply a negative length argument, then that many characters are truncated off the end of the string.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $length = -20;
  my $fragment =  substr $string, 7, $length;
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

    string: <Now is the time for all good people to come to the aid of their party>
  fragment: <the time for all good people to come to th>

Supplying negative arguments might seem weird, but that's OK, because Perl is weird. These negative arguments save you the bother of having to work out where the end of the string is. (And that can be very useful).

Example 3. An expression, an offset value, a length and a replacement value

It's time to confess something. The string we've been using in our examples is an old typing exercise. The original typist's example assumed that only good men could come to the aid of their party! So let's supply the word 'men' as the fourth argument, and see that substr() then modifies $string, returning it to it's old-fashioned form.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  my $fragment =  substr $string, index($string, 'people'), 6, 'men';
  print "  string: <$string>\n";
  print "fragment: <$fragment>\n";

    string: <Now is the time for all good men to come to the aid of their party>
  fragment: <people>

As you can see, our call to substr() has replaced the word 'people' with the word 'men'. By supplying a fourth argument, we have modified the expression $string. At the same time, substr() still returns the substring 'people'.

Example 4. Assigning to substr()

It is perhaps more common to see the modification demonstrated in the previous example achieved by direct assignment. In technical terms, this means that the substr() function can be used as an lvalue, something that can be assigned a value.

  #!/usr/bin/perl
  use strict;
  use warnings;

  my $string = 'Now is the time for all good people to come to the aid of their party';
  substr($string, index($string, 'people'), 6) = 'women';
  print "  string: <$string>\n";

    string: <Now is the time for all good women to come to the aid of their party>

 

 
 

'perl' 카테고리의 다른 글

Array 다루기 #1  (0) 2008.06.05
Passing Parameters to Functions  (0) 2008.06.05
bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
펄 Hash 관련 정보 #1  (0) 2007.10.19
Posted by '김용환'
,

 

bash에서는 다음과 같이 적혀있다.

 Bash does not understand floating point arithmetic. It treats numbers containing a decimal point as strings.

 

그래서,floating 변수를 비교하기 위해서는 문자열 비교를 해야 하는 황당한 이유가 있다.

 

그래서 펄을 이용하면 floating 연산을 할 수 있다.

 

 

다음은 1분간 평균로드가 30이 넘어서면, restart를 자동으로 하게 하는 펄 스크립트이다.

 

if( floating 변수 > integer 변수가)  statement 가 가능하다!!

 

 #!/usr/bin/perl

my $DT                      = `date '+%Y%m%d'`;
chomp $DT;
use constant maxUptimeVal   => 30;
use constant LOG_DIR        => "/home/www/backup";
my $LOG_FILE_NAME           = "auto-start.".$DT.".log";


$loadnum = `cat /proc/loadavg | awk '{print \$1}'`;

if ($loadnum > maxUptimeVal) {
    $r=`/home/www/script/restart-service.sh`;
    debug("restart");
}

sub debug {
my $CDTTM                   = `date '+%Y%m%d%H%M%S'`;
chomp $CDTTM;
    open(LOG, ">>".LOG_DIR."/".$LOG_FILE_NAME);
    print LOG "[".$CDTTM."]".$_[0];
    print "[".$CDTTM."]".$_[0];
    close(LOG);
}

'perl' 카테고리의 다른 글

Passing Parameters to Functions  (0) 2008.06.05
Perl의 String 관련 함수  (0) 2008.03.22
펄 해쉬 이야기 #2  (0) 2007.10.19
펄 Hash 관련 정보 #1  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
Posted by '김용환'
,

펄 해쉬 이야기 #2

perl 2007. 10. 19. 00:10

 

출처

 

http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/hash/


Perl Hash Howto

This how-to comes with no guaratees other than the fact that these code segments were copy/pasted from code that I wrote and ran successfully.

Initialize (clear, or empty) a hash

Assigning an empty list is the fastest method.

Solution

    my %hash = ();

Note

People have asked how to initialize a hash reference (aka hash ref). It's just like any scalar variable; you can use my alone, or you can assign a value.

    my $hash_ref;
    my $hash_ref = 0;  # zero

Add a key/value pair to a hash

In the solutions below, quotes around the keys can be omitted when the keys are identifiers.

Hash:

Solution

    $hash{ 'key' } = 'value';    # hash

    $hash{ $key } = $value;      # hash, using variables

Hash reference:

Solution

    $href->{ 'key' } = 'value';  # hash ref

    $href->{ $key } = $value;    # hash ref, using variables

Add several key/value pairs to a hash

Solution

The following statements are equivalent, though the second one is more readable:

    %hash = ( 'key1', 'value1', 'key2', 'value2', 'key3', 'value3' );

    %hash = (
        key1 => 'value1',
        key2 => 'value2',
        key3 => 'value3',
    );

Copy a hash

Solution

    my %hash_copy = %hash;  # copy a hash

    my $href_copy = $href;  # copy a hash ref

Delete a single key/value pair

The solution differs for a hash and a hash reference, but both cases can use the delete function.

Solution

Hash:

    delete $hash{$key};

Hash reference:

    delete $hash_ref->{$key};

Perform an action on each key/value pair in a hash

The actions below print the key/value pairs.

Solution

Use each within a while loop. Note that each iterates over entries in an apparently random order, but that order is guaranteed to be the same for the functions keys and values.

    while ( my ($key, $value) = each(%hash) ) {
        print "$key => $value\n";
    }

A hash reference would be only slightly different:

    while ( my ($key, $value) = each(%$hash_ref) ) {
        print "$key => $value\n";
    }

Solution

Use keys with a for loop.

    for my $key ( keys %hash ) {
        my $value = $hash{$key};
        print "$key => $value\n";
    }

Example

    my $file = $ARGV[0] || "-";

    my %from = ();

    open FILE, "< $file" or die "Can't open $file : $!";

    while( <FILE> ) {
        if (/^From: (.*)/) { $from{$1}++ }  # count recurrences of sender
    }

    close FILE;

    for my $sender ( sort keys %from ) {
        print "$sender: $from{$sender}\n";
    }

Get the size of a hash

Solution

    print "size of hash:  " . keys( %hash ) . ".\n";

Solution

    my $i = 0;

    $i += scalar keys %$hash_ref;  # method 1: explicit scalar context
    $i += keys %$hash_ref;         # method 2: implicit scalar context

Use hash references

Solution

    sub foo
    {
        my $hash_ref;

        $hash_ref->{ 'key1' } = 'value1';
        $hash_ref->{ 'key2' } = 'value2';
        $hash_ref->{ 'key3' } = 'value3';

        return $hash_ref;
    }

    my $hash_ref = foo();

    print "the keys... ", sort keys %$hash_ref, "...\n";

Function to build a hash of hashes; return a reference

Solution

    sub foo
    {
        my ( $login, $p, $uid, $gid, $gecos, $dir, $s );

        my %HoH = ();

        my $file = '/etc/passwd';
        open( PASSWD, "< $file" ) or die "Can't open $file : $!";

        while( <PASSWD> ) {
            ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );

            $HoH{ $login }{ 'uid' } = $uid;
            $HoH{ $login }{ 'gid' } = $gid;
            $HoH{ $login }{ 'dir' } = $dir;
        }

        close PASSWD;

        return \%HoH;
    }

Access and print a reference to a hash of hashes

Solution

    my $rHoH = foo();

    my( $uid, $gid, $dir );

    for my $login ( keys %$rHoH ) {

        $uid =       $rHoH->{ $login }->{ 'uid' };   # method 1  most readable
        $gid =    ${ $rHoH->{ $login } }{ 'gid' };   # method 2
        $dir = ${ ${ $rHoH }{ $login } }{ 'dir' };   # method 3 least readable

        print "uid: $uid, gid: $gid, dir, $dir.\n";
    }

Solution

    my $rHoH = foo();

    for my $k1 ( sort keys %$rHoH ) {
        print "k1: $k1\n";
        for my $k2 ( keys %{$rHoH->{ $k1 }} ) {
            print "k2: $k2 $rHoH->{ $k1 }{ $k2 }\n";
        }
    }

Function to build a hash of hashes of hashes; return a reference

Solution

    sub foo
    {
        my %HoHoH = ();

        while( ... ) {

            if( /LOCATION:/ ) {

                ...

            } elsif( /MODULE:/ ) {

                $HoHoH{ $loc }{ $module_type }{ MODULE_NAME } = $module_name;

            } elsif( $ARGS_ALLOWED ) {

                $HoHoH{ $loc }{ $module_type }{ $arg_name } = $arg_value;

            }

        }

        return \%HoHoH;
    }

Access and print a reference to a hash of hashes of hashes

Solution

    my $rHoHoH = foo();

    for my $k1 ( sort keys %$rHoHoH ) {
        print "$k1\n";

        for my $k2 ( sort keys %{$rHoHoH->{ $k1 }} ) {
            print "\t$k2\n";

            for my $k3 ( sort keys %{$rHoHoH->{ $k1 }->{ $k2 }} ) {
                print "\t\t$k3 => $rHoHoH->{ $k1 }->{ $k2 }->{ $k3 }\n";
            }
        }
    }

Print the keys and values of a hash, given a hash reference

Solution

    while( my ($k, $v) = each %$hash_ref ) {
        print "key: $k, value: $v.\n";
    }

Determine whether a hash value exists, is defined, or is true

Solution

    print "Value EXISTS, but may be undefined.\n" if exists  $hash{ $key };
    print "Value is DEFINED, but may be false.\n" if defined $hash{ $key };
    print "Value is TRUE at hash key $key.\n"     if         $hash{ $key };

Example

Let's say we execute an sql query where some of the resulting values may be NULL. Before attempting to use any of the values we should first check whether they are defined, as in the following code. Note that the subroutine sql_fetch_hashref() takes care of connecting to the database, preparing the statement, executing it, and returning the resulting row as a hash reference using DBI's fetchrow_hashref() method.

    my $answers = 'a,b,c,d,e';

    my $sql = "select max_time, $answers from questions " .
              'where question_number=?';
    my $hash_ref = sql_fetch_hashref( $sql, $q );

    my @answers = split ',', $answers;

    my $max_time = $hash_ref->{max_time} || '60';

    my $hash_ref_ans;
    for my $letter ( @answers ) {
        $hash_ref_ans->{ $letter } = $hash_ref->{ $letter }
            if defined $hash_ref->{ $letter };
    }

The for loop made a new hash of only defined key/value pairs.


AUTHOR

Alex BATKO <abatko AT cs.mcgill.ca>

Thanks to all those who have written with suggestions and comments.


SEE ALSO

http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/

http://exitloop.ca/abatko/computers/programming/perl/howto/

'perl' 카테고리의 다른 글

Perl의 String 관련 함수  (0) 2008.03.22
bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 Hash 관련 정보 #1  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
패턴 매칭  (0) 2007.09.23
Posted by '김용환'
,

펄 Hash 관련 정보 #1

perl 2007. 10. 19. 00:09

 

출처 :http://www.ebb.org/PickingUpPerl/pickingUpPerl_6.html

Associative Arrays (Hashes)

This chapter will introduce the third major Perl abstract data type, associative arrays. Also known as hashes, associative arrays provide native language support for one of the most useful data structures that programmers implement--the hash table.

What Is It?

Associative arrays, also frequently called hashes, are the third major data type in Perl after scalars and arrays. Hashes are named as such because they work very similarly to a common data structure that programmers use in other languages--hash tables. However, hashes in Perl are actually a direct language supported data type.

Variables

We have seen that each of the different native data types in Perl has a special character that identify that the variable is of that type. Hashes always start with a %.

Accessing a hash works very similar to accessing arrays. However, hashes are not subscripted by numbers. They can be subscripted by an arbitrary scalar value. You simply use the {} to subscript the value instead of [] as you did with arrays. Here is an example:

use strict;
my %table;
$table{'schmoe'} = 'joe';
$table{7.5}  = 2.6;

In this example, our hash, called, %table, has two entries. The key 'schmoe' is associated with the value 'joe', and the key 7.5 is associated with the value 2.6.

Just like with array elements, hash elements can be used anywhere a scalar variable is permitted. Thus, given a @hash{%table} built with the code above, we can do the following:

print "$table{'schmoe'}\n";    # outputs "joe\n"
--$table{7.5};                 # $table{7.5} now contains 1.6

Another interesting fact is that all hash variables can be evaluated in the list context. When done, this gives a list whose odd elements are the keys of the hash, and whose even elements are the corresponding values. Thus, assuming we have the same %table from above, we can execute:

my @tableListed = %table;  # @tableListed is qw/schmoe joe 7.5 1.6/

If you happen to evaluate a hash in scalar context, it will give you undef if no entries have yet been defined, and will evaluate to true otherwise. However, evaluation of hashes in scalar context is not recommended. To test if a hash is defined, use defined(%hash).

Literals

"Hash literals" per se do not exist. However, remember that when we evaluate a hash in the list context, we get the pairs of the hash unfolded into the list. We can exploit this to do hash literals. We simply write out the list pairs that we want placed into the hash. For example:

use strict;
my %table = qw/schmoe joe 7.5 1.6/;

would give us the same hash we had in the previous example.

Functions

You should realize that any function you already know that works on arrays will also work on hashes, since you can always evaluate a hash in the list context and get the pair list. However, there are a variety of functions that are specifically designed and optimized for use with hashes.

Keys and Values

When we evaluate a hash in a list context, Perl gives us the paired list that can be very useful. However, sometimes we may only want to look at the list of keys, or the list of values. Perl provides two optimized functions for doing this: keys and values.

use strict;
my %table = qw/schmoe joe smith john simpson bart/;
my @lastNames  = keys %table;    # @lastNames is: qw/schmoe smith simpson/
my @firstNames = values %table;  # @firstNames is: qw/joe john bart/

Each

The each function is one that you will find particularly useful when you need to go through each element in the hash. The each function returns each key-value pair from the hash one by one as a list of two elements. You can use this function to run a while across the hash:

use strict;
my %table = qw/schmoe joe smith john simpson bart/;
my($key, $value);  # @cc{Declare two variables at once}
while ( ($key, $value) = each(%table) ) {
    # @cc{Do some processing on @scalar{$key} and @scalar{$value}}
}

This while terminates because each returns undef when all the pairs have been exhausted. However, be careful. Any change in the hash made will "reset" the each function for that hash.

So, if you need to loop and change values in the hash, use the following foreach across the keys:

use strict;
my %table = qw/schmoe joe smith john simpson bart/;
foreach my $key (keys %table) {
    # Do some processing on $key and $table{$key}
}

Slices

It turns out you can slice hashes just like you were able to slice arrays. This can be useful if you need to extract a certain set of values out of a hash into a list.

use strict;
my %table = qw/schmoe joe smith john simpson bart/;
my @friends = @table{'schmoe', 'smith'};   # @friends has qw/joe john/

Note the use of the @ in front of the hash name. This shows that we are indeed producing a normal list, and you can use this construct in any list context you would like.

Context Considerations

We have now discussed all the different ways you can use variables in list and scalar context. At this point, it might be helpful to review all the ways we have used variables in different contexts. The table that follows identifies many of the ways variables are used in Perl.

Expression Context Variable Evaluates to
$scalar scalar $scalar, a scalar the value held in $scalar
@array list @array, an array the list of values (in order) held in @array
@array scalar @array, an array the total number of elements in @array (same as $#array + 1)
$array[$x] scalar @array, an array the ($x+1)th element of @array
$#array scalar @array, an array the subscript of the last element in @array (same as @array -1)
@array[$x, $y] list @array, an array a slice, listing two elements from @array (same as ($array[$x], $array[$y]))
"$scalar" scalar (interpolated) $scalar, a scalar a string containing the contents of $scalar
"@array" scalar (interpolated) @array, an array a string containing the elements of @array, separated by spaces
%hash list %hash, a hash a list of alternating keys and values from %hash
$hash{$x} scalar %hash, a hash the element from %hash with the key of $x
@hash{$x, $y} list %hash, a hash a slice, listing two elements from %hash (same as ($hash{$x}, $hash{$y})


Go to the first, previous, next, last section, table of contents.

If you find this book useful, and you play online poker, consider signing up for a poker site using the affiliate links below. These raise revenue to help Bradley pay for the cost of hosting this book draft:

'perl' 카테고리의 다른 글

bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
패턴 매칭  (0) 2007.09.23
Expect (shell)문제 및 해결  (0) 2007.08.24
Posted by '김용환'
,

패턴 매칭

perl 2007. 9. 23. 05:27

 

#!/usr/bin/perl

$r=" I am 20 year old.";
if ($r =~ /\d+/) {
    print "tar is $&.\n";
}  

 

결과

 

[i61841 /home/www/work/temp]# ./test1.pl
tar is 20.

 

매치 연산자는 5가지가 있다.

g : 매치하는 것을 모두 찾는다.

i : 대문자와 소문자를 구별하지 않는다.

m : 문자열을 복수행으로 취급한다.

s : 문자열을 단일행으로 취급한다.

x : 패턴 내에 포함되는 반각 스페이스를 무시한다.

'perl' 카테고리의 다른 글

bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
펄 Hash 관련 정보 #1  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
Expect (shell)문제 및 해결  (0) 2007.08.24
Posted by '김용환'
,

패턴 매칭

perl 2007. 9. 23. 05:14

 #!/usr/bin/perl

 

$r = "I love cat and dog." =~ /love (.+) and (.+)./;

print $1."\n";           # cat
print $2."\n";           # dog
print $&."\n";           # love cat and dog
print $+."\n";           # dog
print "------------------------\n";

 

"hot cross buns" =~ /cross/;
print "Matched: <$`> $& <$'>\n";    # Matched: <hot > cross < buns>
print "Left:    <$`>\n";            # Left:    <hot >
print "Match:   <$&>\n";            # Match:   <cross>
print "Right:   <$'>\n";            # Right:   < buns>

 

재미있는 소스다.

 

$1, $2,  첫번째 두번째 그룹... 이렇게 그룹에 매치되는 문자열을 의미한다.

$& 는 전체 매치된 문자열이다.

$+ 는 마지막 그룹에 매치되는 문자열이다.

$`(grave accent) 는 매치되는 문자열의 왼쪽 단어이고,

$' (single quotation)는 매치되는 문자열의 오른쪽 단어이다.

'perl' 카테고리의 다른 글

bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
펄 Hash 관련 정보 #1  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
Expect (shell)문제 및 해결  (0) 2007.08.24
Posted by '김용환'
,

배경

tcl기반의 expect 스크립트는 동작이 완료되지 않는다..

특히 기존 스크립트는 set timeout 5를 하지만, 실제로 timeout이 되지 않아서.. 속을 썩이고 있었다.

proc do_restart {HOST_NAME} {
set timeout 5
        spawn /usr/local/bin/rlogin -l www $HOST_NAME
        expect -re "]# "
        send "cd /home/www\r\n"
        expect -re "]# "
        send "exit\r\n"
        #expect -re "]# "
        interact
}

중간에 문제가 생기면, 마치 이런 상태가 된다. 이 프로세스를 죽이려면, 해당 서버에 들어가서 프로세스를 죽여야 하는 불상사가 생긴다.

Connection closed.
spawn /usr/local/bin/rlogin -l www iza123
Last login: Thu Jun 28 18:23:42 from 9.1.0.2
#################################################################
# This Server is assigned Web Service 
#################################################################
exit
^M

그래서, expect에서 문제가 생겼을 때 expect 자체에서 해결방법은 찾기 어려웟, 대신 timeout을 제대로 주어. Shell로 빠져나오게 하는 방법은 알아냈다.

#!/usr/bin/expect -f
proc do_restart {HOST_NAME} {
spawn /usr/local/bin/rlogin -l www $HOST_NAME
        expect -re "]# " {
                send "cd /home/www\r\n"
        } timeout {
 send_user "### Time out during connecting $HOST_NAME!! ###\r\n"
                exit
        }
        expect -re "]# "
        send "exit\r\n"
        #expect -re "]# "
        interact
}

if {$argc < 1} {
 puts "Usage : restart <project name>"
 exit
}

set NUM 1000
set HOST [lindex $argv 0]

puts "Target Servers $HOST"
for {set i 0} {$i < $NUM} {incr i 1} {
    do_restart $HOST
}

puts "Target Servers $HOST, test completed"

expect에서 문제가 생겼을 때 제대로 쉘로 되돌아올 수 있게 할 수 있다.

Connection closed.
spawn /usr/local/bin/rlogin -l www ida2
Last login: Thu Jun 28 18:30:37 from 1.1.0.1
#################################################################
# This Server is assigned Web Service 
#################################################################
### Time out during connecting ida2!! ###
[dev1:/home1/knight/test]

하지만 expect 쉘 자체 성능은 꽤나 좋지 않습니다. 타임아웃으로 shell이 종료되는 것은 expect가 좋지 않다는 것!!

Perl로 이동

expect 기능이 perl에도 있음을 찾아냈다. CPAN이라는 그룹에서 만든 expect는 tcl기반이 아니었다.

Expect기능이 perl의 모듈로 되어 있어서, e65008서버에 expect.pm (perl module)을 설치하였다. 그리고, 이 expect로 사용성 테스트해보았는데, ssh, rlogin으로 spawn을 만번정도 각각 테스트를 해보았는데, 한번도 fail나지 않았다.

아주 훌륭하지 않은가.

Expect 설치

expect 모듈을 설치한다. make install은 root계정으로 해야한다.

wget expect모듈 (wget http://nchc.dl.sourceforge.net/sourceforge/expectperl/Expect-1.20.tar.gz)
tar zxvf Excpect-1.20.tar.gz
cd Expect-1.20
perl Makefile.PL
make
make install

현재 expect 모듈 위치는 다음과 같다.
perl의 expect 모듈을 이용하여 wrapper를 만든다.
path가 걸려있는 /usr/local/bin에 펄 코드를 위치시켜 놓아, shell script에서 바로 호출할 수 있도록 한다.

#!/usr/bin/perl
use Expect;

my $spawn;
my $timeout = 10;
my $result;
my $command;
my $prompt  = '[\]\$\>\#]\s$'; 

if ($#ARGV < 0) 
{
    printUsage();
    exit 0;
} 

while($#ARGV >= 0) 
{
    my $option = shift(@ARGV);
    if($option eq "-s") 
    {
        $spawn = trim(shift(@ARGV));
    } 
    elsif($option eq "-timeout") 
    {
        $timeout = trim(shift(@ARGV));
    } 
    elsif($option eq "-r") 
    {
        $result = trim(shift(@ARGV));
    } 
    elsif($option eq "-c") 
    {
        $command = trim(shift(@ARGV));
    }
}

if (!$spawn) 
{
    print "spawn is not given.";
    exit -1;
}

#if (!$result) 
#{
#    print "expect value is not given.";
#    exit -1;
#}

if (!$command) 
{
    print "command is not given.";
    exit -1;
}

my $exp = Expect->spawn($spawn)
    or die "Cannot spawn ".$spawn.": $!\n";

my $qr_result;
if ($result eq "") {
   $qr_result = $prompt; 
} else {
   $qr_result = $result;
}
print $qr_result;
$exp->expect($timeout,
             [qr "$qr_result" => \&exec],
             [timeout => \&timeouterr],
);

sub timeouterr
{
    die "###### timeout!! ######\n";
}

sub printUsage 
{
    print "Usage\n";
    print "  expect.pl -s [spawn] -r [expect value] -c [command] \n";
    print "  expect.pl -s [spawn] -r [expect value] -c [command] -timeout [timeout time] \n";
    print "\n";
    print " ex) ./expect.pl -s \"rlogin -l knight iabcde.google.com\" -r \"] \" -c \"restart.sh;exit\" -timeout 10 \n";
    print " * default timeout value is 2 seconds.\n";
}

sub exec
{
    my $lexp = shift;
    $lexp->send("$command\n");
    exp_continue;
}

sub debug 
{
    print $_[0]."\n";
}

sub trim($) 
{
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

자 코드를 만들었으니, 제대로 동작이 되는지 확인한다.

perl -c expect.pl

문제가 없으면, 다음의 결과가 나올 것이다.

[a50236:/usr/local/bin]# perl -c expect.pl
expect.pl syntax OK

하지만, 다음의 종속 모듈때문에 링킹 에러가 나는 경우가 존재한다.

[a50236:/data/env/project]# perl -c /usr/local/bin/expect.pl 
Can't locate IO/Pty.pm in @INC (@INC contains: /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.0 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.0 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 .) at /usr/lib/perl5/site_perl/5.8.0/Expect.pm line 22.
BEGIN failed--compilation aborted at /usr/lib/perl5/site_perl/5.8.0/Expect.pm line 22.
Compilation failed in require at /usr/local/bin/expect.pl line 2.
BEGIN failed--compilation aborted at /usr/local/bin/expect.pl line 2.

문제는 IO/Pty.pm 모듈의 종속 모듈인데, 다운받는다.

wget IO-Tty모듈  (wget http://www.cpan.org/modules/by-module/IO/IO-Tty-1.07.tar.gz)

IO/Pty.pm을 설치한다. make install은 root계정으로 해야한다.

wget expect모듈 (wget http://nchc.dl.sourceforge.net/sourceforge/expectperl/Expect-1.20.tar.gz)
tar zxvf Excpect-1.20.tar.gz
cd Expect-1.20
perl Makefile.PL
make
make install

테스트 bash shell script는 다음과 같이 만든다.

[esz18:/home/www/work]# cat expect.sh
#!/bin/bash
eval 'exec expect.pl -s "rlogin -l knight dev1.google.com" -c "exit" -timeout 3'

제약사항

물론 이 코드는 커보러스/rlogin 환경에서만 적절히 사용될 수 있다. 환경에 따라 커스터마이징을 할 필요가 있다.

참조

http://search.cpan.org/~rgiersig/Expect-1.20/Expect.pod
http://iama.rrecktek.com/syslog/installsnare.pl

'perl' 카테고리의 다른 글

bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
펄 Hash 관련 정보 #1  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
패턴 매칭  (0) 2007.09.23
Posted by '김용환'
,