13

I am having a perl script which opens a file and write some data in it. Sometimes this file is having read only permissions on some machines. For such cases, at present the script dies as it was not able to open the file. My requirement is that in such cases, I want my script to continue and instead of writing the contents in file, puts it in STDOUT. I will use the warn instead of die, but I want to know can I alias my file handle FILE1 to STDOUT such that I need not have to modify the remaining code, reason being in my actual code print FILE1 <> is present at many places and is not possible for me to put if\else conditions everywhere. I want that I will alias FILE1 to STDOUT such that print statement will either output it in STDOUT or write in file depending upon the value set in FILE1 filehandle. Is it possible using perl?

$file = "testfile.txt";
open( FILE1, ">> $file" ) or die "Can not read file $file: $! \n";
print FILE1 "Line1 \n";
print FILE1 "Line2 \n";
print FILE1 "Line3 \n";
print FILE1 "Line4 \n";
close FILE1
sarbjit
  • 3,786
  • 9
  • 38
  • 60
  • Possible duplicate of http://stackoverflow.com/questions/3807231/how-can-i-test-if-i-can-write-to-a-filehandle – devnull Apr 17 '13 at 13:11

1 Answers1

23

You can do so with *FILE1 = STDOUT;.

Variables with a * in front are called typeglobs. Read about them here.

You may also want to start using lexical file handles

This is how i would solve your problem:

use strict;
use warnings;

my $file = "testfile.txt";
my $succ = open( my $fh , '>>', $file );

$fh = *STDOUT unless $succ;

print $fh "Line1 \n";
print $fh "Line2 \n";
print $fh "Line3 \n";
print $fh "Line4 \n";

close $fh if $succ; # don't close STDOUT
tauli
  • 1,420
  • 8
  • 13
  • I just added this code after my open statement and it worked. Could you please tell me how I could check whether filehandle is opened succesffully or not. Right now even if the file is accessible, it is just printing the text in STDOUT and NOT in file. – sarbjit Apr 17 '13 at 13:16
  • 2
    `open( FILE1, ">> $file" ) or *FILE1 = STDOUT;` would be a very simple way. –  Apr 17 '13 at 13:18
  • @dan1111 how would you distinguish a FILE1 pointing to $file from FILE1 pointing to STDOUT? I just wonder because closing STDOUT may not be a good idea. – tauli Apr 17 '13 at 13:30
  • 1
    @tauli, well, you could check if `*FILE1 eq *STDOUT`. However, I not bother to close `FILE1` at all unless there was a specific need to do so (such as it is a long-running program, or I need to open lots of other filehandles). The interpreter automatically closes open files at exit. –  Apr 17 '13 at 13:43
  • @tauli, also note that if you use a lexical filehandle, it is automatically closed when it goes out of scope. –  Apr 17 '13 at 13:57
  • @dan1111 You can't just compare typeglobs for string equality; this just compares the fully qualified names (→ always false for different globs). Comparing the IO slot would be better (`*FILE1{IO} == *STDOUT{IO}`), as these hold an object representing the filehandle, and references (incl. objects) numify to an unique ID. – amon Apr 17 '13 at 14:24
  • @amon, hmmm. I did test it: `*FILE1=STDOUT; print "Same" if *FILE1 eq *STDOUT;`. Prints "Same" for me (Strawberry 5.16). –  Apr 17 '13 at 14:32
  • 1
    @amon, unless I am missing something, I believe `*FILE1=STDOUT` means they are both pointing to the same symbol table, so they will evaluate to equal. Witness this stupid code: `*FILE1=STDOUT; @FILE1 = ("foo"); $STDOUT = "bar"; print @STDOUT,$FILE1;` –  Apr 17 '13 at 14:37
  • @dan1111 Oh, well, I got that wrong then. Thanks for your correction :) – amon Apr 17 '13 at 15:37