When writing Perl scripts to automate shell tasks, file handlers will be used for reading files, writing to files, executing commands, redirecting output, … But these handlers can only be opened in one direction if they are created with the standard Perl subroutine open
.
In some cases it is actually required to create a two way communication with the file handler, for instance when creating a pipe. In a pipe, some information is written to the pipe (left side of the pipe) which is read and analyzed by the right side of the pipe. This right of the pipe, is then able to produce some output.
If it is required to catch that output, we will need to have two file handlers!
A core module called IPC::Open2
provides an open2
subroutine, which allows to create a read and write file handler.
In the following example, we will mimic the shell command cat file|file -rik -
, without calling the cat
command. Instead we will open the file in RAW mode using Perl and then use file handlers to feed it to the file
command and afterwards read the output.
#!/usr/bin/perl use strict; use warnings; use IPC::Open2; my @files = (qw{ parse_svn_log.zip scan_new.xsd bla.pl ../../root.tgz ../../bla.tar ../../Toyota.pdf ../../sms.bak scan.xml }); foreach my $file (@files) { print("Scanning $filen"); open my $fh, '<:raw', $file or die "schijt: $!n"; my $fc = <$fh>; close ($fh); my $mime = _get_mime_type($fc); print("- file: $file | mime: $mimen") if defined $mime; } sub _get_mime_type { my($data) = @_; my $mime = do { open2(my $read, my $write, 'file -rik -'); print {$write} $data."n"; close($write); local $/; <$read>; }; chomp($mime); if(defined $mime and $mime !~ m/^s*$/) { # 1) remove the '/dev/stdin:' part # 2) MIME type are always in the format: blabla/blabla # 3) in some rare cases their is a semicolon at the end # e.g.: /dev/stdin: application/x-symlink; charset=binary $mime =~ s/.*?://s; ($mime) = ($mime =~ /(S+?/S+)/s); $mime =~ s/;.*$//g; } else { $mime = 'text/plain'; } return $mime; }
Output produced by script:
Scanning parse_svn_log.zip - file: parse_svn_log.zip | mime: application/zip Scanning scan_new.xsd - file: scan_new.xsd | mime: application/xml Scanning bla.pl - file: bla.pl | mime: text/x-perl Scanning ../../root.tgz - file: ../../root.tgz | mime: application/x-gzip Scanning ../../bla.tar schijt: No such file or directory
The other way to deal with these legacies is to use ODBC connection..