why can I open undef? - perl

The following does not die:
open my $in, '<', undef or
die q{couldn't open undef};
print <$in>;
Neither does this:
open my $in, '>', undef or
die q{couldn't open undef};
print $in 'hello';
I don't understand why neither of these die. How could opening undef possibly be successful?
The reason I found this was that a guy I work with had done this:
open my $in, '>', $ARGV[0] or die q{couldn't open $ARGV[0]};
He thought that this would kill the script if no arguments were passed in (I know this isn't the cleanest way to do that but I didn't think it wouldn't work).
I'm using Strawberry 5.16.1.

See perldoc -f open:
As a special case the three-argument form with a read/write mode and
the third argument being undef:
open(my $tmp, "+>", undef) or die ...
opens a filehandle to an anonymous temporary file.

Related

How can I reopen a closed file handle in Perl?

Once a file handle is closed is it possible to reopen it without creating a new file handle?
ex (This doesn't work):
use strict;
use warnings;
# Open and write to a file
open my $fh, '>', 'file.txt' or die $!;
print $fh 'Hi!';
close $fh;
# Reopen the file and read its contents
open $fh, '<' or die $!;
my #contents = <$fh>;
close $fh;
print #contents;
I'm trying to avoid doing this:
open my $fh2, '<', 'file.txt' or die $!;
You cannot "reopen" it. The best solution is to avoid closing, if you
need it later. Remember that you can alway use seek if you need
to rewind to some portion of the file.
# open for read/write
open my $fh, '+<', 'file.txt' or die $!;
# do something to file, like writing
# go to the beginning
seek FILEHANDLE, 0, 0;
# do something else, like reading
I don't know that you can reopen a closed handle. But, you can reuse the $fh variable as a filehandle since it's been closed. But, you're missing the name of the file when you open again.
open $fh, '<', 'file.txt' or die $!;

Can I find out what Perl IO Layer(s) a given filehandle has?

Is it possible to find out what IO Layer a Perl filehandle has on it?
For example:
open(my $fh, '<:encoding(UTF-8)', $filename)
or die "Unable to open '$filename': $!";
say io_layer($fh); # prints "encoding(UTF-8)"
The following returns the names of the PerlIO layers on a filehandle.
my #layers = PerlIO::get_layers($fh); # Or FH, *FH, "FH".
more details in PerlIO doc.

Opening files in-memory means what?

You can open file handles in-memory ?
The in-memory part is unclear to me, what does that mean ?
If that means you can use the computer's memory, Isn't it already working like that ?
It means you can use filehandles to write to and read from scalar variables.
my $var = "";
open my $fh, '>', \$var;
print $fh "asdf";
close $fh;
print $var; # asdf
Ultimately, this is just One More Way To Do
$var .= "asdf"
but there are contexts where is more convenient or more appropriate to use filehandle paradigms than string manipulation paradigms.
For example, start with this code:
open my $fh, '>', $logfile;
...
print $fh $some_message_to_be_logged;
... 500 more print $fh statements ...
close $fh;
But you know what? Now I'd rather record my log messages in a scalar variable, maybe so I can search through them, manipulate them before they are written to disk, etc. I could change all my print statements to
$logvar .= $some_message_to_be_logged
but in this case it is more convenient to just change the open statement.
open my $fh, '>', \$logvar
You can open Filehandles directly to scalar variables. Its especially useful when you have something that has to behave like a file, but you dont want one on disk. This example is taken from perldoc:
close STDOUT;
open(STDOUT, ">", \$variable)
or die "Can't open STDOUT: $!";
It closes STDOUT and then reopens it attached to $variable.

Creating a file name using variables in Perl

I am trying to write out to a file, where the file name is created from a variable(the name + the user id + the date and time + file extension).
I have read various things on Stackoverflow which I have based my code off.
my $windowsfile = "winUserfile-$User_ID-$datetime.csv";
open winUserfile, ">>", $windowsfile) or die "$!";
print winUserfile "User_ID, Expression\n";
close winUserfile;
I would assumed this would work, but I am getting a syntax error. Would anyone be able to help?
Your second line has a close-paren without the preceeding open:
open winUserfile, ">>", $windowsfile) or die "$!";
You likely want to open it first
open(winUserfile, ">>", $windowsfile) or die "$!";
Or just not bother with them entirely here, as they're optional in this case
open winUserfile, ">>", $windowsfile or die "$!";
Also, it's bad style to use a bareword filehandle, as this creates becomes global. Better to use a lexical one:
open my $winUserfile, ">>", $windowsfile or die "$!";
print $winUserfile "User_ID, Expression\n";
You don't then need to close it; the close will be automatic when the $winUserfile variable goes out of scope.
I like using the IO::All module for file io.
use IO::All
my $windowsfile = "winUserfile-$User_ID-$datetime.csv";
io($windowsfile) > "User_ID, Expression\n";
my $windowsfile = "winUserfile-$User_ID-$datetime.csv";
open (winUserfile, ">>$windowsfile") or die "$!";
print winUserfile "User_ID, Expression\n";
close winUserfile;

What's the easiest way to write to a file using Perl?

Currently I am using
system("echo $panel_login $panel_password $root_name $root_pass $port $panel_type >> /home/shared/ftp");
What is the easiest way to do the same thing using Perl? IE: a one-liner.
Why does it need to be one line? You're not paying by the line, are you? This is probably too verbose, but it took a total of two minutes to type it out.
#!/usr/bin/env perl
use strict;
use warnings;
my #values = qw/user secret-password ftp-address/;
open my $fh, '>>', 'ftp-stuff' # Three argument form of open; lexical filehandle
or die "Can't open [ftp-stuff]: $!"; # Always check that the open call worked
print $fh "#values\n"; # Quote the array and you get spaces between items for free
close $fh or die "Can't close [ftp-stuff]: $!";
You might find IO::All to be helpful:
use IO::All;
#stuff happens to set the variables
io("/home/shared/ftp")->write("$panel_login $panel_password $root_name $root_pass $port $panel_type");
EDIT (By popular and editable demand)
http://perldoc.perl.org/functions/open.html
In your case you would have to :
#21st century perl.
my $handle;
open ($handle,'>>','/home/shared/ftp') or die("Cant open /home/shared/ftp");
print $handle "$panel_login $panel_password $root_name $root_pass $port $panel_type";
close ($handle) or die ("Unable to close /home/shared/ftp");
Alternatively, you could use the autodie pragma (as #Chas Owens suggested in comments).
This way, no check (the or die(...)) part needs to be used.
Hope to get it right this time. If so, will erase this Warning.
Old deprecated way
Use print (not one liner though). Just open your file before and get a handle.
open (MYFILE,'>>/home/shared/ftp');
print MYFILE "$panel_login $panel_password $root_name $root_pass $port $panel_type";
close (MYFILE);
http://perl.about.com/od/perltutorials/a/readwritefiles_2.htm
You might want to use the simple File::Slurp module:
use File::Slurp;
append_file("/home/shared/ftp",
"$panel_login $panel_password $root_name $root_pass ".
"$port $panel_type\n");
It's not a core module though, so you'll have to install it.
(open my $FH, ">", "${filename}" and print $FH "Hello World" and close $FH)
or die ("Couldn't output to file: ${filename}: $!\n");
Of course, it's impossible to do proper error checking in a one liner... That should be written slightly differently:
open my $FH, ">", "${filename}" or die("Can't open file: ${filename}: $!\n");
print $FH "Hello World";
close $FH;
For advanced one-liners like this, you could also use the psh command from Psh, a simple pure Perl shell.
psh -c '{my $var = "something"; print $var} >/tmp/out.txt'
I use FileHandle. From the POD:
use FileHandle;
$fh = new FileHandle ">> FOO"; # modified slightly from the POD, to append
if (defined $fh) {
print $fh "bar\n";
$fh->close;
}
If you want something closer to a "one-liner," you can do this:
use FileHandle;
my $fh = FileHandle->new( '>> FOO' ) || die $!;
$fh->print( "bar\n" );
## $fh closes when it goes out of scope
You can do a one-liner like this one:
print "$panel_login $panel_password $root_name $root_pass $port $panel_type" >> io('/home/shared/ftp');
You only need to add the IO::All module to your code, like this:
use IO::All;
Some good reading about editing files with perl:
FMTYEWTK About Mass Edits In Perl