http://qs321.pair.com?node_id=1081238

juanpablo has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys,

I'm BASH guy actually and I think this is my fifth time writing a Perl script but I'm more than willing to learn this language. In fact, I could see I will be the happiest guy if I have completely learned this. :) Anyway, I'm currently writing a script that will easily add new virtual hosts to httpd.conf. However, I am always getting the "uninitialized value $_" error when starting the script.

Use of uninitialized value $_ in string at ./test.pl line 32.

Usage: ./test.pl --domain companydomain.com --client company --job-code 12345 --help.

Here is my code:
#!/usr/bin/perl use strict; use warnings; use POSIX 'strftime'; use File::Basename; use File::Copy; use File::Find::Rule; use Getopt::Long; # Variables. my $dir = '/etc/httpd/conf'; my $filename = 'httpd.conf'; my @object = File::Find::Rule ->file() ->name($filename) ->in($dir); my $conf = "$_"; my $conf_bn = basename($conf); my $conf_mtime = (stat($conf))[9]; my $date = strftime '%m%d%Y', localtime; my $backup = "$conf.$date"; my $backup_bn = basename("$conf.$date"); my $ltime = localtime(); my $domain = undef; my $client = undef; my $job_code = undef; # Display usage. sub usage { die "Usage: $0 --domain companydomain.com --client company [--job- +code 12345] [--help].\n"; } &usage() unless @ARGV > 2; GetOptions ( 'domain=s' => \$domain, 'client=s' => \$client, 'job-code:i' => \$job_code, 'help' => &usage() ) or &usage(); sub add_vhost { if (-e $conf) { open (CONF, ">>$conf") || die "ERROR: Unable to open $conf_bn. +\n"; print CONF "\n# Domain: $domain"; print CONF "# Client: $client"; print CONF "# Job Code: $job_code"; print CONF "# Date: $ltime"; print CONF "<VirtualHost *:1111>"; print CONF " ServerAdmin admin@$domain"; print CONF " DocumentRoot /var/www/html/$domain"; print CONF " ServerName $domain"; print CONF " ServerAlias www.$domain"; print CONF " ErrorLog /var/log/httpd/$domain/$domain-error_ +log"; print CONF " CustomLog /var/log/httpd/$domain/$domain-acces +s_log common"; print CONF "</VirtualHost>"; print CONF "# End of configuration for $domain."; close CONF; if ($? != 0) { die "ERROR: $!.\n"; } } } foreach (@object) { # my $conf = "$_"; # my $conf_bn = basename($conf); # my $conf_mtime = (stat($conf))[9]; # my $date = strftime '%m%d%Y', localtime; # my $backup = "$conf.$date"; # my $backup_bn = basename("$conf.$date"); # my $ltime = localtime(); # Backup of old configuration. copy ($conf, $backup) || die "ERROR: Unable to create a backup. $! +.\n"; if ($? == 0) { utime $conf_mtime, $conf_mtime, $backup || die "ERROR: Unable +to preserve stats."; # Update time using old file's mtime. if ($? == 0) { print "OK: $backup_bn has been created.\n"; } } # New configuration update. &add_vhost(); }

Since I always get the error, I tried switching the place of the variables above to the body of foreach and when I do that, I'm getting these errors...

Global symbol "$conf" requires explicit package name at ./test.pl line 59.

Global symbol "$conf" requires explicit package name at ./test.pl line 60.

Global symbol "$conf_bn" requires explicit package name at ./test.pl line 60.

Global symbol "$ltime" requires explicit package name at ./test.pl line 64.

Execution of ./test.pl aborted due to compilation errors.

I'm stumped and I couldn't find anything on Google that would help resolve this. By the way, I'm just new here at PerlMonks. :)

Thanks in advance!

Cheers,

JP

Replies are listed 'Best First'.
Re: Use of uninitialized value $_ in string
by toolic (Bishop) on Apr 05, 2014 at 13:33 UTC
    my $conf = "$_";
    I suspect the warning is coming from that line (which is not line 32 in the code you posted). I don't think you ever set the $_ special variable before you used it. Also, there is usually no reason to place quotes around a scalar variable. Also, what you get is a warning, not an error. It appears because you use warnings;, which is a good idea because it notifies you that there is something unexpected in your code.

    The other errors you see are like due to coping with scoping.

      Hi toolic!

      Thanks for the reply! I appreciate it.

      Yes, you're right. I've just realized that that variable shouldn't be declared on top. I've removed it already and put it back in foreach body. Also, the errors were gone but I'm not sure if that's the right thing to do, I mean the declaration of variables again in the sub part. I'm checking the coping with scoping thread now. :)

      Cheers,

      JP

Re: Use of uninitialized value $_ in string
by frozenwithjoy (Priest) on Apr 05, 2014 at 13:27 UTC

    What is on line 32 for you? When I put your script into my editor, line 32 is:

    die "Usage: $0 --domain companydomain.com --client company [--job-code + 12345] [--help].\n";

    Is it my $conf = "$_"; ?? If so, what are you trying to do here?

      Hi frozenwithjoy,

      Yes, the line 32 is my $conf = "$_";. I've managed to remove the errors but I'm not so sure if this is the correct approach especially the declaration of the same variables under sub add_vhost. What I did was...

      remove these variables from above:

      my $conf = "$_"; my $conf_bn = basename($conf); my $conf_mtime = (stat($conf))[9]; my $date = strftime '%m%d%Y', localtime; my $backup = "$conf.$date"; my $backup_bn = basename("$conf.$date"); my $ltime = localtime();

      then declared the $conf, $conf_bn, and $ltime variables under sub add_vhost.

      sub add_vhost { my $conf; my $conf_bn; my $ltime;

      and removed the comments from the variables under foreach...

      foreach (@object) { my $conf = "$_"; my $conf_bn = basename($conf); my $conf_mtime = (stat($conf))[9]; my $date = strftime '%m%d%Y', localtime; my $backup = "$conf.$date"; my $backup_bn = basename("$conf.$date"); my $ltime = localtime();

      The errors were gone every time I execute the script. However, after providing two required arguments, the script still does nothing. I was expecting it would start creating a backup of the existing file.

      [root@wsprod01 myperl]# ./test.pl --domain google.com --client google Usage: ./test.pl --domain companydomain.com --client company [--job-co +de 12345] [--help].

      Cheers,

      JP

        ... the script still does nothing.
        [root@wsprod01 myperl]# ./test.pl --domain google.com --client google Usage: ./test.pl --domain companydomain.com --client company [--job-co +de 12345] [--help].

        In the code shown in the OP, in the statement

        GetOptions ( 'domain=s' => \$domain, 'client=s' => \$client, 'job-code:i' => \$job_code, 'help' => &usage() ) or &usage();
        the  'help' key is given the value of whatever is returned by a call to the  usage() function. Problem is, this function returns nothing; rather, it calls die to print a usage message, so program execution will never get past the  GetOptions() function call. Is this what you intend?

        Updates:

        1. If you want to assign the  'help' key a reference to the  usage() function,
              'help' => \&usage,
          would be the correct expression.
        2. Added italic emphasis in "... a call to the  usage() function."