Last Updated:

Programming CGI scripts in Perl

Minimal Introduction to Pearl

This section provides the minimum necessary information on those elements of Pearl that are most often used when writing scripts. Pearl here is considered as a C-like language, so the differences from C are emphasized. This section in no way pretends to describe the Language of Pearl (many points are deliberately omitted); for this purpose, refer to camel Book, Llama Book or Maslov's book.

The comment "from here to the end of the line" is the "#" character.

 

Variable Types

Variables are of three types: scalars, lists, and hashes. You don't need to describe variables unless you're using the "use strict" directive; otherwise, each variable must be described using "my variable_name".

Scalars

The scalar contains a single value; it can be a string or a number, Pearl himself determines the type of value from the context of the operations performed with the scalar. For example, if you try to concatenate two scalars with the "." operation, they will be treated as strings, and if you try to add their values with the "+" operation, they will be treated as numbers. When performing numeric operations on strings whose value cannot be interpreted as a number, the numeric value of such a scalar is considered to be zero (see also operators, expressions and operations below).

Repeat especially for programmers in C: string values do not end with the character "\0". String values as such do not exist at all, a string is one of two ways to interpret the value of a scalar, which in itself does not end with anything special.

The names of all scalar variables must begin with $ ($x, $my_variable_1).

 

  • There is a special scalar value undef - "uncertainty". Such a value has, for example, variables that have not been assigned any value. In logical and arithmetic operations, undef is considered zero, in string operations - an empty string. The defined(expression) function returns truth if the expression is not equal to undef (although it can be zero).
    my $x; # $x is created, equals undef
    $x; # false
    defined($x); # false
    $x=0;
    $x; # false
    defined($x); # true
    $x=5;
    $x; # true
    defined($x); # true
    $x=undef; # undef again!

    Lists and arrays

    A list is an ordered sequence of scalar values; sequence numbers (indexes) start with zero. Separate lists are enclosed in brackets:

    ($x, "abc", 15)
    
    A list item is accessed by specifying the index of that item in square brackets:
    $y=($x, "abc", 15)[1];      # $y="abc"
    

    A variable whose value is a list is called an array. All array names must begin with @ (@array). When accessing an array element, the @ sign is replaced with $:

    $array[0]
    $array[$x]
    $array[-2]      # second element from the end 
    (meaning: an array element is a scalar, hence it starts with $). Examples of array formation: Number of elements in an array: scalar @array (see also "Contexts" below); Index of the last item: $last_index = $#array.
    @array=($x, "abc", 15);
    @array=($x, $y, @another_array);
    @array=(); #empty list 

    To retrieve part of an array:

    ($a, $b, $c) = @array[3,4,5];
    @sublist=@array[3,4,5];
    
    Accordingly, on the contrary: it assigns values to part of the array @array (if the elements of the @array[0-2] were previously absent, they are created with undef values).
    @array[3,4,5]=($a,$b,"xyz");

    Two- or more dimensional arrays are not explicitly supported.

    Functions for working with arrays:

     

    @list = reverse @array
    @list = reverse list
    - returns a list consisting of the values of the @array array, taken in reverse order (the array itself does not change @array). The argument to the reverse function can be not only an array, but any expression that has a list value.

     

    push @array, $x
    push @array, list
    - Places a value or list of values at the end of an array. A list can be either an explicit comma-separated enumeration of values or any expression that has a list value. The push function returns the new length of the @array array.

     

    $x = pop @array
    - retrieves the last element from the array (the element from the array is deleted). If an array is not specified, a list of function arguments (i.e., an @_ array) is implied if the call is made inside a function, or the command-line arguments of the script (i.e., an array @ARGV) if the call is made from the main body of the script.

     

    $x = shift @array
    - retrieves the first element from the array (the element from the array is deleted). If an array is not specified, a list of function arguments (i.e., an @_ array) is implied if the call is made inside a function, or the command-line arguments of the script (i.e., an array @ARGV) if the call is made from the main body of the script.

     

    unshift @array, $x
    unshift @array, список
    - Similar to push, but new elements are placed at the beginning of the array @array.

     

    @list = splice @array, $from, $length, список
    @list = splice @array, $from, $length
    @list = splice @array, $from
    - removes @array $length elements from the array, starting with the $from index. If a list is present, values from the list are placed instead of deleted items; if there are more of them than remote ones, then the array increases, if less - then it decreases accordingly. If there is no $length, all items starting with the $from index are deleted. The index $from can be negative - then the account is made from the end, i.e. splice(@array,-2) removes the last two elements from the @array array, and splice(@array,-2,1) deletes the penultimate element. The splice function returns a list of items deleted from the array. The push, pop, unshift, and shift functions are special cases of the splice function.

    Hashes

    A hash variable is an array whose elements are indexed by strings (an associative array). The order in which items in the hash are stored is not defined. The names of all hash variables must begin with % (%my_hash). When accessing a list item, the % character is replaced with $ and curly braces are used:

    $hash{"key_A"}
    $hash{$x}
    
    Hashes can be formed by combining an even number of scalars into parentheses: In general, any list (array) can be treated as a hash, i.e. %hash=@array. In this case, the odd items in the list will become the hash keys, and the even ones will become the corresponding values. If the number of items in the list is odd, the last element of the hash constructed in this way will exist with the value undef ("uncertainty"). If there are identical items in the list at odd positions, the hash will include a value whose key is the last of the identical odd items in the list.
    %hash=("abc", $x, "def", 15);
    # $hash{abc}=$x and $hash{def}=15
    #commas for readability can be replaced with "=>"
    %hash=("abc" => $x, "def" => 15);
    %hash=();
    #empty hash
    @array=('a',1,'b',2,'c');
    # no match for 'c'
    %hash=@array;
    # got: $hash{c}=undef
    %hash=('a' => 1, 'b' => 2, 'a' => 3);
    # got: $hash{a}=3

    The converse is also true: any hash can be treated as a list. For example, an inversion of the hash works using the reverse function, which takes a list in the weight of the argument and returns the same list backwards (see below).

    Functions for working with hashes:

     

    @array = keys %hash
    - Returns a list of hash keys (the order is uncertain).

     

    @array = values %hash
    - returns a list of hash values (the order is indeterminate, but for the same hash always coincides with the order in which keys are issued).

     

    ($key, $value) = each %hash
    - returns a list of two scalars: the key and the value of the next hash element; is used in loops to pass through all elements of the hash.

     

    exists $hash{$key}
    - Returns a true (non-zero) value if the specified hash element exists (although it may be zero or has an indeterminate value).

     

    delete $hash{$key}
    - Deletes the specified hash element.

     

    %rev_hash = reverse %hash
    - swaps the keys and values of the hash elements; works correctly if there were no elements with the same values in the %hash hash.

     

    Operators, Expressions, and Operations

    Pearl's operators, expressions, and operations are similar in many ways to the C language.

    Contexts

    Each expression in Pearl is evaluated in a list or scalar context. That is, in a list context, it is assumed that the value of an expression should be a list, and in a scalar context, a scalar. The context is determined, for example, by the type of variable on the left side of the assignment statement. Many functions define the context in which they were invoked and return different results depending on the context. For example, the function localtime (current local time) in a scalar context returns a string of the form "Fri Nov 26 20:36:33 1999", and in the list context - a list of numbers: seconds, minutes, hours, day of the month, month, etc. In order to force the scalar context, you can use the scalar operator.

    $x = localtime; # scalar context
    @time = localtime; # list context
    ($sec,$min,$hour) = localtime[0,1,2]; # list context
    print scale localtime; # scalar context

    The value of a list in a scalar context is the length of the list:

    $x=@array;
    # the length of the @array list is placed in the variable $x
    The value of a scalar in a list context is a list consisting of one scalar.

    Expression values and operations

     

    • Most arithmetic and logical operations are similar to C operations (including operations of type $x++; ++$x; $x += 5; $x=$y=5). The differences are discussed below.

       

    • The result of many operations can be considered as a true (non-zero) or false (zero or indefinite) value. You can use the "||" or "or" operations to build a chain of actions that are performed based on the success (true value) or failure of the previous action. This allows you to shorten the write (otherwise you would have to use the if statement).
      # open the file myfile.txt, giving it a FILE descriptor,
      # or exit the program with an error message
      open(FILE, "myfile.txt") or die("Cannot open file");

      # display a message if the hash element exists
      exists $hash{"mykey"} and print "My key exists!";

      # set $x to 5,
      # if $x is undefined or null
      $x ||= 5;

       

    • There are a number of operations for working with scalars as strings. Operation"." (dot) causes string concatenation: Scalar comparisons as strings are performed by the following operations:
      $x = "Now is " . scalarlocaltime;
      $x .= " (time is local)."; # same as $x = $x . " (time is local).";  
      $a eq $bTrue if $a and $b are the same
      $a ne $bTrue if $a and $b are not the same
      $a lt $bTrue, if $a earlier alphabetically than $b
      $a gt $bTrue, if $a later alphabetically than $b
      $a le $bTrue if the $a earlier alphabetically or coincides with the $b
      $a ge $bTrue if the $a later alphabetically or coincides with the $b
      $a cmp $b-1 if $a earlier alphabetically than $b; 0 if the $a and $b are the same; 1 if $a later alphabetically than $b

      Warning, a common mistake! The operations "== != > < >= <=" compare scalars as numbers. Using them in a "scalar-string" context will lead to incorrect results. For example, "11">"2" but "2"gt"11". Moreover, $a="xyz"; $b="qwerty"; $a==$b is true because as numbers both of these variables are zero.

       

    • An additional operation to compare scalars as numbers: $x<=>$y equals -1 if $x<$y; 0 if $x=$y; 1, if $x>$y.

       

    • If the expression does not specify where the data is coming from or where it is returned, it is assumed that it is the variable $_ (in the scalar context) or @_ (in the list context).
      # read from a file with FILE descriptor one line at a time (<FILE> statement)
      # and remove the newline character from the end of the read line (chomp function)
      while ($a=<FILE>) { chomp $a; }
      # the same, using the $_ variable
      while (<FILE>) { chomp; }  

      Operators

       

    • There are similar operators to the C language Differences and additions are discussed below.
      if (...) {...};
      condition ? expression_yes : expression_no ;
      while(...) {...}; do {...} while (...); for (...;...;...;) {...};

       

    • Curly braces that define the block of operators executed after a branch or loop operator should always exist, even if the statement block consists of a single operator: However, for branch operators in this case, there is a shortened "postfix" form of the notation:
      if ($a<$b) { $a=$b; }
      while ($a<$b) { some_function($a); }
      
      $a=$b if ($a<$b);
      

       

    • Brackets around standard function arguments are not required (unless there is ambiguity):
      print "a=",$a;
      НО: join ':', split ('/', $a); or
          join ':', split ('/'), $a;

       

    • The foreach statement loops through all the items in the list:
      foreach $i (@array) {
         print $i;
      }
      # same with $_ variable
      foreach (@array) {
         print;
      }

       

    • The unless operator is an if operator with negation: Be careful when programming complex conditions with unless - remember de Morgan's theorem: the negation of a product is the sum of negations; the negation of the sum is the product of the negations.
      # set $x to 5,
      # if $x is undefined or null
      unless ($x) { $x=5; } # same as $x ||= 5;

       

    • The until operator is a while statement with negation: respectively and do {...} until(...).
          until ($array[$i++] == $x) {;} 
      

       

    • There is no switch statement. Use the if construct () ... elsif () ... elsif () ... else ... or invent something of your own.

      Loop Management:

      • early transition to the next iteration of the nearest encompassing cycle - next (analogous to the continue operator in C):
               foreach $i (@array) {
        	      next if ($i<0);
        		  $sum += $i;
        	   }
        
      • early exit from the nearest enveloping cycle - last (analogous to the break operator in C):
            # read lines from a file and print,
               # until an empty string is encountered
               while ($a=<FILE>) {
        chomp$a;
        last unless($a);
        print $a, "\n";
        }
      • Each loop can be labeled by the next and last operators. this allows you to exit several enveloping cycles at once:
        # this is not the best algorithm for finding the same words in two lists,
          # but here we use the exit from two loops at once
          M1: foreach $i (@array1) {
                   foreach $j (@array2) {
        if ( $i eq $j ) { last M1; }
        }
        }

     

    Quotation marks and interpolation

    String expressions are enclosed in single (') or double (") quotation marks. Everywhere inside double quotation marks, variables are substituted - scalars, list items and hash elements; Entire lists are substituted as a substring in which all list items follow each other without a delimiter. the entire hashes are not substituted. To escape special characters inside double quotation marks, a reverse slash is used: \$, \@, \", \\; all special characters of the C language are also recognized: \n, \t, etc.

    $x="abc";
    @array=('c','d','e');
    %hash=( a => "A", b=> "B");
    print "this is \$x: \"$x\"; \nthis is element 2 of \@array: \"$array[2]\";\n",
          "and \$hash{a} is \"$hash{a}\"\n";
    ВЫВОД:
    this is $x: "abc";
    this is element 2 of @array: "e";
    and $hash{a} is "A"
    

    Strings used as hash keys, if they are literal strings without substitutions ("abc"), can be omitted from: $hash{abc}.

    Within single quotation marks, no substitutions are made, special characters of the "\n" type are not integrated and all symbols are taken literally; Exception: The combination \' (a reverse slash is a single quotation mark) that is intepreted as a single quotation mark that is part of a string. A single quotation mark inside double quotation marks is taken literally.

     

    Working with regular expressions

    Regular expressions

    Pearl's regular expressions (PB) are a superset of the PB grep/awk used in Unix. In the PB, the following symbols have special meanings:

    \ | ( ) [ { ^ $ * + ? . /

    The characters "]" and "}" have special meanings only when they occur after "[" and "{", respectively. All other symbols in RV are taken literally. The "/" character has a special meaning not in a regular expression, but as a sign of the beginning and end of a regular expression (see examples below). The most commonly used PB metacharacters and their meanings are summarized below.

     

    . (dot)
    - any single character other than \n (unless the modifier s is used - see below).

     

    *
    - Zero or more appearances of the PB immediately preceding the symbol.

     

    +
    - one or more appearances of the PB immediately preceding the symbol.

     

    ?
    - Zero or one occurrence of the PB immediately preceding the symbol.

     

    ^
    - The beginning of the line.

     

    $
    - End of line.

     

    [characters] 
    [^characters]
     
    - One character from the (un)listed inside parentheses. All metacharacters within square brackets lose their special meaning, except for the character "^" if it is located immediately after the opening bracket (in this case, it denotes the negation of the character set); if the character "^" is not immediately after the opening parenthesis, it is taken literally. If the character "]" is directly behind the opening parenthesis or immediately behind the combination "[^", it is taken literally and not as a closing parenthesis; in this case, there must be another closing parenthesis.

     

    (РВ)
    - Grouping the regular expression PB. It is also used for subsequent reference to the part of the string that corresponds to the PB.

     

    |
    - operation "OR" - at least one of the RCs to the left and right of the symbol "|" must be triggered.

     

    \s
    - any probe symbol (same as [ \t\n\r\f]).

     

    \w
    - Any alphanumeric character (same as [a-ZA-Z_0-9]).

     

    \d
    - Any digit (same as [0-9]).

     

    \b
    - Word boundary.

     

    \S, \W, \D, \B
    - Negation of regular expressions, respectively, \s, \w, \d, \w.

     

    $variable
    - Substitution of the value of the variable.

     

    \
    - screens the next metacharacter so that it is taken literally.

    Regular expressions are enclosed in a pair of slashes: /PB/, which can be followed by modifiers:

    • i - ignore the difference between uppercase and lowercase letters (in general, for Latin only),
    • s - perceive the scalar expression to be processed as consisting of several strings separated by \n characters (i.e. the ^ and $ metacharacters will be triggered on \n characters that may occur within the scalar expression being processed),
    • m - treat the scalar expression to be processed as a single string, regardless of whether the \n characters occur within that expression or not (i.e., the ^ and $ metacharacters will not fire on \n characters, but the metacharacter will fire on \n).

    Note that the metacharacters $, ^, \b do not absorb the characters of the string being processed, i.e. for example, ^ is not the first character of the string, but the beginning of the string as such; similarly, \b is not the first or last character of a word, but the boundary between characters like \W and \w. In other words, the word cat corresponds to PB /^c/, and the word act does not correspond to it; or in the string "a yellow cat", the regular expression /\byellow\b/ corresponds to the substring "yellow" rather than "yellow" or "ello".

    Mapping operator

    Search for PB in the string:

    $s =~ /rv/modifiers; 
    $s !~ /rv/modifiers;
    The operation returns True in the scalar context if the string $s (not) matches the PB, otherwise it returns False. If $s is not specified, $_ is used.
    if ( $d =~ /vvsu\.ru$/ ) { ... }
    if ( /^From: /i) { ... }
    

    Replacement operator

    Replacing part of a string:

    $s =~ s/rv/replacement/modifiers; 
    The operation searches for a substring of the $s string that corresponds to the PB, and then replaces that substring with a replacement. If the modifier g is specified, all substrings corresponding to the PB are replaced, otherwise only the first substring found is replaced. The operation returns the number of replacements that have been made. If $s is not specified, $_ is used. Variable substitution can be used in both RV and replacement. In the replacement part, you can also use special symbols of $ 1.$ 2,..., which will substitute the corresponding part of the RV, taken in brackets. Examples:
    #in the line $x swap the first two fields;
    #$1 refers to the first parenthesized expression in the first part of the statement,
    # $2 - for the second
    $x =~ s/([^ ]*) *([^ ]*)/$2 $1/;

    #remove dot from end of string $_
    s/\.$//;

    #replace all white words with black in $_ variable
    s/\bwhite\b/black/ig;

    #replace in $_ all #include_date expressions with the current date
    #use the e modifier to indicate
    #that the second part of the statement should be interpreted as a pearl code
    s/#include_date/localtime/eg;

    #same, but the text "#include_date" is stored in the $date_token variable
    s/$date_token/localtime/eg;

     

    Work with files and run other programs

    Files are read and written through a file descriptor variable. The name of such a variable does not have a special prefix and, as a rule, is written in uppercase letters. The dexiptor is created when the open function is called. File handles do not need to be pre-declared even when using "use strict".

    Open a file

    open (FILE, "filename") or die ("Cannot open filename: $!");
    
    The open function returns "falsely" if the file cannot be opened, in which case the die function is executed, which prints its argument and exits the script. Variable S! - A standard Pearl variable that contains a description of the last system error that occurred.

    FILE is a handle to the file, it will be used below in the operations of reading, writing and closing the file.

    The following example opens the filename file for reading. To open a file for writing from scratch, its name must be preceded by the symbol ">" (if the file previously existed, its contents will disappear); for opening to add to the end - precede with symbols ">>":

    open (FILE, ">filename") or die ("Cannot open filename: $!");
    open(FILE, ">>filename") or die("Cannot open filename: $!");
    #open for reading and writing
    open(FILE, "+>filename") or die("Cannot open filename: $!");
    For any script, when it is run, the STDIN, STDOUT, and STDERR handles are opened by default.

    Reading from a file

    The <FILE> statement reads from a file with a FILE handle. In a scalar context (for example, in the while loop condition), the operator returns the next line of text up to and including the next line feed when called. The list context returns a list of all text strings from the current position to the end of the file.

    # scalar context
    while (<FILE>) {
       chomp;
       if ($_eq "this text") {
         do_something();
       }
    }

    # list context
    @all_lines=<FILE>;

    Warning, a common mistake! A string read from a file most likely ends in a line feed (unless it is the last line in the file and the file ends with a line feed). This character is often forgotten and they try to compare the read value with some other value that does not contain, of course, a line feed. Use the chomp function to get rid of this character at the end of the line.

    Another common mistake! The statement (empty inside the parentheses) reads not from standard input, but from files whose names are specified as command-line arguments. When one file is complete, the input continues from the beginning of the next file in the order in which the file names are specified on the command line. You do not need to open files when using the operator.

    Writing to a file

     

    print FILE "this line is printed to FILE\n"; 

    Close a file

     

    close FILE;
    
    Although Pearl closes all unpatched files when exiting the script, it is strongly recommended that you do so by explicitly calling the close function to avoid various side effects.

    Output to the program

    To transfer data to the standard input of another program, you need to create a corresponding file descriptor using open (the program will be launched) and output data to it. To create such a handle, the second argument passes the path to the program preceded by the "|" character to the open function:

    open (MAIL, "|/usr/bin/mail $user") or die($!);
    print MAIL "Subject: Happy birthday!\n\n",
               "Hi, $user! Happy birthday!";
    close MAIL;		   
    

    Entering from the program

    To receive data from the standard output of another program, you need to create a corresponding file descriptor using open (the program will be launched) and enter data from it. To create such a handle, the second argument to the open function is passed to the path to the program, followed by the symbol "|":

    open (LS, "/usr/bin/ls $dir |") or die($!);
    @dir_listing= <LS>;
    close LS;		   
    

    Rename, delete, and change its attributes

     

    # rename file
    rename $oldname, $newname or die($!);

    # delete files (returns the number of successfully deleted files)
    unlink $this_file, $that_file, @and_whole_list_of_files;

    # change file attributes
    # (returns the number of files whose attributes have been changed)
    chmod 0755, @array_of_filenames;

    # change file owners ($uid and $gid must be numeric)
    # (returns the number of files whose owners have been changed)
    chown $uid, $gid, @array_of_filenames;
    Run another program

    To execute another program from a script, the system function is used, the argument of which is the argc[] list (i.e., the command line of the program being extracted, starting with the name of the program itself).

    system $program_to_run, $argument1, $argument2, ...;
    
    The function returns 0 when the program is successfully terminated and X*256 if the exit status of the program was X.

     

    Working with strings

    This point describes some of Pearl's useful functions for working with strings (functions for working with regular expressions are discussed above).

    Parse a string

    The split function splits a scalar value interpreted as a string using the specified delimiter and returns the result as a list.

    @list = split;
    @list = split delimiter;
    @list = split delimiter, string;
    @list = split delimiter, string, limit;

    The limit specifies that the row will be split into no more than the part limit (in other words, only the first limit-1 separators will be accepted; the entire remainder will be returned in the last item in the list). If there is no limit, then all delimiters encountered in the row will participate in the partition.

    If the string is missing, $_ is processed.

    The separator can be a regular expression (enclosed in a slash: /PB/) or a literal string (enclosed in quotation marks: 'string'). If there is no separator, then /\s+/ is implied ("one or more space characters in a row"); i.e. split without arguments is equalent "split /\s+/, $_".

    Example:

    # list all system users with their UIDs
    open(PASSFILE, "/etc/passwd") or die($!);
    while (<PASSFILE>) {
       chomp;
       #unnecessary elements of the list are discarded
       ($user, $junk, $uid) =split ':';
       print "User $user has UID $uid\n";
    };

    Generate a row from a list of items

    join

    join 'separator', @list; 

    The join function generates a scalar string consisting of list items, separating the values of the items from each other with a delimiter.

    $_ = join ' | ', "a", "b", "c";
    print;
    #OUTPUT: "a | b | c"

    # change delimiters from colon to comma with space
    $_ = join ', ' (split, ':');

    sprintf
    The sprintf function works in the same way as in the C language.

    Find a substring in a string

    index

    $position = index $string, $substring, $start_position;
    $position = index $string, $substring;
    The index function returns the position in the string where the substring begins (meaning the first occurrence of the substring, if there are more than one). If the starting position is specified, then the search begins from this position, otherwise - from the beginning of the line. The positions in the row are numbered starting from zero. If no substring is found, the function returns -1.
    # sequential search for all occurrences of $lookfor in $string
    $pos = -1;
    while (($pos=index($string, $lookfor, $pos)) > -1) {
       print "Found at position $pos\n";
       $pos++;
    }

    rindex

    The rindex function is similar to index, but returns the position of the last occurrence of a substring in a string. In this case, the third argument, if specified, determines the position at which the search should be stopped.

    Extract a substring from a string at a known position

    $substring = substr $string, $offset, $length;
    $substring = substr $string, $offset;
    The substr function extracts a substring of length from the string that begins at the offset position. If no length is specified, the substring is retrieved from the offset to the end of the line. The positions in the row are numbered starting from zero.

    If the offset is negative, then it is counted not from the beginning, but from the end of the line. If the length is negative: length=-N, then this means that a substring of such length is extracted that it ends with N characters before the end of the string.

    # all of the following operations set $_ to "abc"
    $_ = substr "xyzabcqqqq", 3, 3;
    $_ = substr "xyzabcqqqq", 3, -4;
    $_ = substr "xyzabcqqqq", -7, 3;
    $_ = substr "xyzabcqqqq", -7, -4;

    Insert/replace part of a row at a known position

    To insert a substring into a string or replace one substring with another substring, use the substr function on the left side of the assignment statement. In this case, the first argument to the substr function must be a scalar expression that can be assigned a value—a scalar variable, an array element, or a hash element. Examples (each example assumes that $a="abcdef"):

    # 1) adding the substring "HELLO" to the beginning of the value of the variable $a
    substr($a,0,0) = "HELLO";
    # $a contains "HELLOabcdef"

    # 2) replacing the second and third characters in the string $_ with the word "HELLO"
    substr($a, 1, 2) = "HELLO";
    # $a contains "aHELLOdef"

    # 3) insert the word "HELLO" between the third and fourth characters in the string $a
    substr($a, 3, 0) = "HELLO";
    # $a contains "abcHELLOdef"


    # 4) replace the last character in string $a with the word "HELLO"
    substr($a, -1, 1) = "HELLO";
    # $a contains "abcdeHELLO"

    The above operations can be understood as follows: the specified substring is extracted from the variable $a, and then the word "HELLO" is inserted instead of it at the same position.

    Other functions

    # removes one character from the end of string $a; returns the removed character
    chop$a;

    # removes the newline character from the end of the line, if present,
    # otherwise the line remains unchanged;
    # returns the number of characters removed
    chomp$a;

    #returns the length of string $a
    $l = length $a;

    #translates all characters of string $a to uppercase
    uc$a;
    #translates the first character of string $a to uppercase
    ucfirst $a;

    #translates all characters of string $a to lowercase
    lc$a;

    If no arguments above are given, $_ is assumed.

    Writing Functions


Functions are described anywhere in the script using the construct

sub function_name {
   function_body;
}

and are called in the usual way: Parentheses are required when calling user-written functions.

function_name(argument1, argument2, ...); # with list of arguments
function_name(); # no arguments

The number and type of arguments are not declared and can be any and different with successive calls to the same function; All arguments passed to a function are combined into a single list. inside the function, all arguments are available through the @_ array in the order in which they were specified when the function was called. If there were no arguments, the @_ array is empty. The hash passed as an argument is converted to a list (for the relationship between lists and hashes, see "Types of variables. Hashes".).

sub function1 {
   # absolutely meaningless function - just an illustration of how to take arguments
   my $x = shift; # this removes the first argument from the list @_
                        # if @_ is empty then $x=undef
   my($y,$z) = @_; # and here the arguments from the @_ list are not removed
                        #(if they are there at all, otherwise $y=$z=undef)
   print "Our first argument is ", defined $x ? $x : "empty", "\n";
   $y||=1; # and set $y and $z to their default values
   $z||=1;
}

sub function2 {
  # creepy useful feature
  # assumed to be scalar $k and hash %h as arguments;
  # function returns $h{$k}
  
  my $k = shift;
  # if $k is empty or there is nothing left in the argument list - return undef and exit
  (defined $k and @_) or return undef;
  my %h=@_;
  return $h{$k};
}
# function call (for example):
$value=function2("my_key",%hash);  

Each function returns a value. This can be done explicitly by using the return statement, whose argument is a scalar or a list. If the return statement is not encountered until the end of the function, the value of the last calculated expression is returned. The value returned by any function can be used or ignored by the calling program.

Each function is called in either a scalar or list context; accordingly, the calling program interprets the result returned by the function:

# f() returns a list
@array=f(); # list context - everything is trivial
$x=f(); # scalar context - length is placed in $x
            # the returned list, and it disappears

# s() returns a scalar
@array=s(); # list context - list @array now
             # consists of a single return value
$x=s(); # scalar context - everything is trivial

To determine in which context a function was called, the wantarray operator is used inside the function, which returns the truth if the function was called in a list context. Consider an example of a function that returns a list in a list context and the first list item in a scalar context.

sub f {
   # this is how the @array list is created
   # ...
   return wantarray ? @array : $array[0];
}
push @biglist, f(); # list context, because second
                     # the argument of the push function is expected to be a list
$first=f(); # scalar context  

Warning, a common mistake! If 2 arrays are passed to a function in terms of arguments: f(@ar1,@ar2), then inside the function there is no way to determine where in the list of @_ arguments the first array ends and the second begins. If you want to distinguish between these arrays within a function, you need to pass them to the function as references. The same goes for hashes.