That can't be done in general (portably),† what is understandable given that a "file"handle need not be associated with a file at all. One thing you can do is to record the fileno for each filehandle.
So when opening a file
my %filename_fileno;
open my $fh, '>', $file or die "Can't open $file: $!";
$filename_fileno{fileno $fh} = $file;
and then you can look it up when needed ‡
say "Filename is: ", $filename_fileno{fileno $fh};
Don't forget to remove the entry from the hash when that file is (to be) closed
delete $filename_fileno{fileno $fh};
close $fh;
So these should be in utility functions. Given that more care is needed, as outlined in the footnote ‡, altogether this would make for a nice little module. Then one can also consider to extend (inherit from) a related module, like Path::Tiny.
Note: You cannot write to a file from separate filehandles like in the question. Operations on each filehandle keep track of where that filehandle was last in the file, thus writes will clobber intermediate writes by the other filehandle.
Note: Use lexical filehandles (my $fh
) and not globs (FH
), use the three-argument open
, and always check the open
call.
† On some (most?) Linux systems you can use /proc
filesystem
say readlink("/proc/$$/fd/" . fileno $fh);
and on more (all?) Unix-y systems can use the (device and) inode number
say for (stat $fh)[0,1];
‡ Links, both soft (symbolic) and hard, can be used to change the data and have different names. So we can have different filenames but same "file" (data).
On Windows systems the best way to check is given in this post, except for the hardlink case for which one would have to use the other answer's method (parse output), as far as I can tell.
Also, non-canonical names, as well as different capitalizations (on case insensitive systems), short/long names on some systems, (more?) ... can make for different names for the same file. This is easier to clean up, using modules, but needs to be added as well.
On most (all?) other systems the notion of inode and any available stat
-like functionality makes these a non-issue, since device+inode refers uniquely to data.
Thanks to ikegami for comments on this.