Question

I wrote a script today. The purpose of this is to automatically add new virtual host to Apache. The script should be executed using this command:

./new_vhost.pl --add --domain google.com --client google. 

However, it doesn't work well instead it throws me errors

Use of uninitialized value $domain in concatenation (.) or string

Have you guys experienced this before? I was thinking the cause was the '.' in google.com though I am not really sure about it. I'm still searching for answers on Google but unfortunately nothing could help me fix this.

Code:

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use Cwd;
use POSIX "strftime";

my $dir = getcwd;
my $conf = 'test.conf';

my $domain = undef;
my $client = undef;
my $help = undef;
my $ltime = undef;

if (-e $conf) {
        sub usage {
                die "Usage: $0 [--add | --remove] [--domain google.com] [--client google].\n";
        }

        usage unless @ARGV > 3;
        GetOptions (
                'add' => \&add_vhost,
#               'remove' => \&rem_vhost,
                'domain=s' => \$domain,
                'client=s' => \$client,
                'help' => \&usage
        ) || usage;

        $domain = lc($domain);
        $client = uc($client);
        $ltime = localtime;

        sub add_vhost {
                open (CONF, ">>$conf") || die "ERROR: unable to open $conf.\n";
                print CONF "#***** Start of configuration for $domain. *****#";
                print CONF "\n# Domain: $domain\n";
                print CONF "# Client: $client\n";
                print CONF "# Date: $ltime\n";
                print CONF "<VirtualHost *:1111>\n";
                print CONF "    ServerAdmin admin\@$domain\n";
                print CONF "    DocumentRoot /var/www/html/$domain\n";
                print CONF "    ServerName $domain\n";
                print CONF "    ServerAlias www.$domain\n";
                print CONF "    ErrorLog /var/log/httpd/$domain/$domain-error_log\n";
                print CONF "    CustomLog /var/log/httpd/$domain/$domain-access_log common\n";
                print CONF "</VirtualHost>\n";
                print CONF "#***** End of configuration for $domain. *****#\n";
                close CONF;
                if ($? != 0) {
                        die "Error: unable to create a new configuration.\n";
                } else {
                        print "OK: new configuration for $domain has been added.\n";
                }
        }
} else {
        die "ERROR: $conf not found.\n";

}

Error:

Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 37.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 38.
Use of uninitialized value $client in concatenation (.) or string at ./new_vhost.pl line 39.
Use of uninitialized value $ltime in concatenation (.) or string at ./new_vhost.pl line 40.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 42.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 43.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 44.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 45.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 46.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 46.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 47.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 47.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 49.
Use of uninitialized value $domain in concatenation (.) or string at ./new_vhost.pl line 54.
OK: new configuration for  has been added.

The test.conf after running the script.

#***** Start of configuration for . *****#
# Domain:
# Client:
# Date:
<VirtualHost *:1111>
    ServerAdmin admin@
    DocumentRoot /var/www/html/
    ServerName
    ServerAlias www.
    ErrorLog /var/log/httpd//-error_log
    CustomLog /var/log/httpd//-access_log common
</VirtualHost>
#***** End of configuration for . *****#

But I was expecting something like this...

#***** Start of configuration for google.com. *****#
# Domain: google.com
# Client: GOOGLE
# Date: Tue Apr  8 17:27:39 2014
<VirtualHost *:1111>
    ServerAdmin admin@google.com
    DocumentRoot /var/www/html/google.com
    ServerName google.com
    ServerAlias www.google.com
    ErrorLog /var/log/httpd/google.com/google.com-error_log
    CustomLog /var/log/httpd/google.com/google.com-access_log common
</VirtualHost>
#***** End of configuration for google.com. *****#
Was it helpful?

Solution

When GetOptions is trying to call your add_vhost, the variables $domain and $client may not be initialized.

You could change your code to

my $add = undef;

...

GetOptions (
    'add' => \$add,
...

if ($add) {
    add_vhost();
}

...

By the way, you better move your definition of add_vhost out of that conditional statement, and pass those information such as $domain as arguments to add_vhost instead of using global variables.

OTHER TIPS

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use Cwd;
use POSIX "strftime";

my $dir = getcwd;
my $conf = 'test.conf';

my $domain = undef;
my $client = undef;
my $help = undef;
my $ltime = undef;
my $to_add_vhost = undef;

if (-e $conf) {
        sub usage {
                die "Usage: $0 [--add | --remove] [--domain google.com] [--client google].\n";
        }

        usage unless @ARGV > 3;
        GetOptions (
                'add' => \$to_add_vhost,
#               'remove' => \&rem_vhost,
                'domain=s' => \$domain,
                'client=s' => \$client,
                'help' => \&usage
        ) || usage;

        $domain = lc($domain);
        $client = uc($client);
        $ltime = localtime;

    &add_vhost if (defined $to_add_vhost);

        sub add_vhost {
                open (CONF, ">>$conf") || die "ERROR: unable to open $conf.\n";
                print CONF "#***** Start of configuration for $domain. *****#";
                print CONF "\n# Domain: $domain\n";
                print CONF "# Client: $client\n";
                print CONF "# Date: $ltime\n";
                print CONF "<VirtualHost *:1111>\n";
                print CONF "    ServerAdmin admin\@$domain\n";
                print CONF "    DocumentRoot /var/www/html/$domain\n";
                print CONF "    ServerName $domain\n";
                print CONF "    ServerAlias www.$domain\n";
                print CONF "    ErrorLog /var/log/httpd/$domain/$domain-error_log\n";
                print CONF "    CustomLog /var/log/httpd/$domain/$domain-access_log common\n";
                print CONF "</VirtualHost>\n";
                print CONF "#***** End of configuration for $domain. *****#\n";
                close CONF;
                if ($? != 0) {
                        die "Error: unable to create a new configuration.\n";
                } else {
                        print "OK: new configuration for $domain has been added.\n";
                }
        }
} else {
        die "ERROR: $conf not found.\n";

}

I'd advise some style changes to clean up your code.

  • When checking for an error, die immediately instead of after an else.
  • You can declare your parameters for GetOptions in the actual subroutine call to simplify things.
  • Considering using a HERE_DOC when printing a big block of text.
  • Your error checking on @ARGV before calling GetOptions is unnecessary. Let GetOptions handle that by having your required parameters. As it is, you'll currently fail under a valid calling method --domain=value --client=value' because only 2 elements will be in@ARGV` versus 4.

This cleans up your code to the following:

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

use Getopt::Long;
use Cwd;
use POSIX "strftime";

my $dir = getcwd;
my $conf = 'test.conf';

die "ERROR: $conf not found.\n" if ! -e $conf;

sub usage {
    die "Usage: $0 [--add | --remove] [--domain google.com] [--client google].\n";
}

GetOptions(
    'add'      => \my $add,
#   'remove'   => \&rem_vhost,
    'domain=s' => \my $domain,
    'client=s' => \my $client,
    'help'     => \&usage
) or usage();

$domain = lc($domain);
$client = uc($client);
my $ltime = localtime;

if ($add) {
    add_vhost();
}

sub add_vhost {
    open my $fh, '>>', $conf;

    print $fh <<"END_CONF";
#***** Start of configuration for $domain. *****#
# Domain: $domain
# Client: $client
# Date: $ltime
<VirtualHost *:1111>
    ServerAdmin admin\@$domain
    DocumentRoot /var/www/html/$domain
    ServerName $domain
    ServerAlias www.$domain
    ErrorLog /var/log/httpd/$domain/${domain}-error_log
    CustomLog /var/log/httpd/$domain/${domain}-access_log common
</VirtualHost>
#***** End of configuration for $domain. *****#
END_CONF

    if ($? != 0) {
        die "Error: unable to create a new configuration.\n";
    } else {
        print "OK: new configuration for $domain has been added.\n";
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top