Short answer: system
doesn't return output from a command; it returns the exit value. As the output of the cut
isn't redirected, it prints to the current STDOUT (e.g. your terminal). Use open
or qx//
quotes (aka backticks) to capture output:
@names = `cat /etc/passwd | cut -f 1 -d :`;
As you are still learning Perl, here is a write-up detailing how I'd solve that problem:
First, always use strict; use warnings;
at the beginning of your script. This helps preventing and detecting many problems, which makes it an invaluable help.
Next, starting a shell when everything could be done inside Perl is inefficient (your solution starts six unneccessary processes (two sets of sh
, cat
, cut
)). In fact, cat
is useless even in the shell version; just use shell redirection operators: cut ... </etc/passwd
.
To open a file in Perl, we'll do
use autodie; # automatic error handling
open my $passwd, "<", "/etc/passwd";
The "<"
is the mode (here: reading). The $passwd
variable now holds a file handle from which we can read lines like <$passwd>
. The lines still contain a newline, so we'll chomp
the variable (remove the line ending):
while (<$passwd>) { # <> operator reads into $_ by default
chomp; # defaults to $_
...
}
The split
builtin takes a regex that matches separators, a string (defaults to $_
variable), and a optional limit. It returns a list of fields. To split a string with :
seperator, we'll do
my @fields = split /:/;
The left hand side doesn't have to be an array, we can also supply a list of variables. This matches the list on the right, and assigns one element to each variable. If we want to skip a field, we name it undef
:
my ($user, undef, $id) = split /:/;
Now we just want to print the user. We can use the print
command for that:
print "$user\n";
From perl5 v10 on, we can use the say
feature. This behaves exactly like print, but auto-appends a newline to the output:
say $user;
And voilà, we have our final script:
#!/usr/bin/perl
use strict; use warnings; use autodie; use feature 'say';
open my $passwd, "<", "/etc/passwd";
while (<$passwd>) {
chomp;
my ($user, undef, $id) = split /:/;
say $user;
}
Edit for antique perls
The autodie
module was forst distributed as a core module with v10.1. Also, the feature 'say'
isn't available before v10.
Therefore, we must use print
instead of say
and do manual error handling:
#!/usr/bin/perl
use strict; use warnings;
open my $passwd, "<", "/etc/passwd" or die "Can't open /etc/passwd: $!";
while (<$passwd>) {
chomp;
my ($user, undef, $id) = split /:/;
print "$user\n";
}
The open
returns a false value when it fails. In that case, the $!
variable will hold the reason for the error.