Index

perl IO

system output

print scalar
print 'hello';
print with newline
print 'hello\n';
alternatively
use 5.26.1;
say "hello";
print variables
print $a;
print $a . $b;
print $a , $b;
print a element at index i in an array
say "$array[i] \n"
print arrays (values space separated)
say @a;
say "@array \n"
print full ascii on unix terminal (e.g. letters with accents)
binmode(STDOUT, ":unix:utf8");
no interpolation
say 'do not interpolate $dollar @at';
variable interpolation
say "replace $myvar";
say "replace ${myvar}";
say "escape \$text";
array element interpolation
say "get element 0: $myarray[0]";
say "get element 3: $myarray[1 + 2]";
say "literal \$text[1 + 2]";
say "variable $myvariable\[1 + 2\]";
say "variable ${myvariable}[1 + 2]";
array interpolation
say "space separated @myarray";
say "slice @myarray[1,9]";
say "literal \@myarray";
escaping interpolation chars
print "interpolate \$\{myvar\} \@myarray \$myarray\[0\] $myhash{'key'}";
print with format
printf "%[n]d\n", [number];

system error

print a line to system error
print STDERR "[message]\n";
say STDERR "[message]\n";

system input

read line from input
my $line = <STDIN>;
chomp(my $line = <STDIN>);
read lines from input until EOF (or ctrl-D if on unix system input)
my @lines = <STDIN>;
chomp(my @lines = <STDIN>);
iterate over STDIN
while (<STDIN>) {
        print "$_";
}

file tests

-d $directory
-e $exists
-f $file
-l $link
-r $readable
-s $exists_non_zero_size
-w $writable
-x $executable
-z $zero_byte_file

-A $accessed_in_days
-B $binary_file
-M $modified_in_days
-T $text_file
example: require directory
my $spool = '/tmp/spool';
if ( -e $spool ) {
        -d $spool or die "$spool exists, but is not a directory";
} else {
	mkdir $spool;
}
example: file test using default variable
$_ = '/tmp/file'
say "$file is older than one week" if -C > 7;
example: use _ to refer to file used in last check (more efficient)
-e $spool or die "$spool does not exist";
-d _ or die "$spool exists, but is not a directory";
example: multiple flags in one test
-f -w $file or die "$file is not a writable file";
documentation
perldoc -f -X
https://perldoc.perl.org/functions/-X.html

diamond operator

use the diamond operator to read input from STDIN or files supplied as arguments
while (<>) {
        print "$_";
}
the following fixes a problem that may occur with special characters in file names
use v5.22;
while (<<>>) {
        print "$_";
}
to read input from <STDIN>
perl [script]
to read input from files
perl [script] [file]...
use diamond operator to write changes made to lines, back to the original files
use v5.22;
 # create backup of files with '.bak' extension and modify original files
$^I = '.bak'
while (<<>>) {
	# todo: change $_ to modify file contents
        print "$_"; 
}

environment

command line arguments
say "@ARGV";
the environment variables are in %ENV
foreach(sort keys %ENV) {
        say "$_ = $ENV{$_}"
}

file handles

default file handles
<DATA>
<ARGV>
<ARGVOUT>
<STDIN>
<STDOUT>
<STDERR>
opening a file handle
open [name], '<',  [file] # read
open [name], '>',  [file] # write
open [name], '>>', [file] # append
open <name>, '-|', 'ls';  # read shell command output
open <name>, '|-', 'bc';  # write something to shell command
opening a file handle with encoding
open [name], '<:encoding(UTF-8)',  [file] # read
writing to a file handle
say [handle] [message];
print [handle] [message];
close a file handle
close [name];
example: read file
my $noerror = open FILE, '<', $filename;
if($noerror) {
        while (<FILE>) {
                print "$_";
        }
	close FILE;
} else {
	say "error message: $!"
        die "unable to open file $filename";
}
example: invoke 2 shell commands and pipe the output of the first to the second
open my $in,  '-|', 'ls /' or die $!;
open my $out, '|-', 'sed "s/t/b/"' or die $!;
while ( my $row = <$in> ) {
    print {$out} $row;
}
enable binmode for binary files (don't change line endings)
binmode [handle];
documentation of the open command
https://perldoc.perl.org/functions/open.html

other file operations

get the current working directory
use Cwd;
$cwd = getcwd();
change working directory
chdir $to or die 'unable to change dir to $to; $!';
create a directory
mkdir $directory or die "failed to create directory $!";
mkdir $directory 0777 or die "failed to create directory $!";
glob non-hidden files
my @files = <*>;
my @files = <*.py>;
my @files = glob '*';
my @files = glob '*.py';
glob hidden files
my @files = glob '.*';
my @files = <.*>;
glob all files
my @files = glob '* .*';
my @files = <* .*>;
directory handles
my $dir = '/tmp';
opendir HANDLE, $dir or die "unable to open $!";
foreach (readdir HANDLE) {
        say "file $dir/$_" unless $_ eq '.' or $_ eq '..';
}
closedir HANDLE;
deleting a file
unlink '/tmp/deleteme' or die "unlink failed $!"
deleting multiple files
unlink $file1 $file2 or die "unlink failed $!"
delete empty directory
rmdir $directory or die "unable to delete $directory $!"
rename a file
rename 'from' => 'to'
get softlink details
readlink '/tmp/link'
changing timestamps
utime $acces, $modified, @ARGV;

invoking the shell

invoking the native shell (redirect sys in & out)
my $exit_code = system 'echo $PATH | sed "s/:/\n/g" | sort';
invoking a single command with special characters in argument
my $exit_code = system 'echo', '$*/ \?:;';
setting an environment variable
$ENV{'foo'} = 'bar';
my $exit = system 'echo $foo';
exit perl and invoke shell command
exec 'echo "invoked"';
say "code after exec is never invoked";
call native shell and capture output as a string
my $output = `pwd`;
say "pwd: $output";
call native shell and capture output as a list of strings
my @lines = system 'echo $PATH | sed "s/:/\n/g" | sort';

process signals

sending a signal
kill $signal $process
example: send hup to process id 12488
perl -e "kill 'HUP', 12488";
perl -e "kill 1,     12488";
capturing all signals (if possible)
say "pid $$";
sub handler {
	my $signame = shift;
	say "received interrupt $signame";
	if ($signame eq 'INT') {
		exit 0;
	}
}
for(split ' ', `kill -l`) {
	$SIG{$_} = "handler";
}
sleep 1 while 1;