Wayne has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I am attempting to print data from a variable directly to a CUPS printer - as opposed to a writing a hard-disk file and then sending it to the printer. The reason is because the file system will eventually be a read-only one.

I have created a file handle for the variable that stores the data and populated it. If I print the contents of $variable it is correct.

To send the data to the printer I am opening a file handle for reading and passing it as an argument to a CUPS printer.

However, I am getting a "No such file or directory" error. Yet, the variable and file handle both exist.

Does CUPS not accept a variable tied to a file handle as a parameter or (more likely) am I doing it improperly?

Thanks in advance.

#!/usr/bin/perl -t use strict; use warnings; use Net::CUPS::Destination; # Define Printer my $cups = Net::CUPS->new() or die $!; my $printer = $cups->getDestination("CITIZEN-CT-S801") or die $!; # Read Data my($variable)=''; open(my $fh, '>', \$variable) or die "Cannot open file for writing: $! +\n"; print $fh "Some data 1\n"; print $fh "Some data 2\n"; print $fh "Some data 3\n"; close($fh); # Print Data open($fh, '<', \$variable) or die "Cannot open file for reading: $!\n" +; if ($printer->printFile($fh, 'jobx')) { print 'Success';} else { my $error = $printer->getError(); if ($error) { print "Printer Error: " . $error . "\n"; } } close($fh); exit;

Replies are listed 'Best First'.
Re: CUPS Printing - Using a Variable as a Filename
by Corion (Patriarch) on Aug 20, 2019 at 15:43 UTC

    ->printFile is documented to take a file name. You give it a file handle, which is not the same, and thus won't work.

    You will have to create a named file, write your data to it and then print it via CUPS, as I don't see any approach to print from memory using Net::CUPS.

Re: CUPS Printing - Using a Variable as a Filename
by Fletch (Bishop) on Aug 20, 2019 at 15:43 UTC

    Reading the perldoc printFile says it takes a filename not a filehandle: "You must provide the name of the file and a title for the job."

    You might could use File::Temp (possibly after setting $ENV{TMPDIR} to something like /dev/shm depending on the OS) and write there, then pass that path to printFile.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      possibly after setting $ENV{TMPDIR} to something like /dev/shm depending on the OS

      Note that File::Temp supports a DIR parameter to create the temporary files in specific locations.

Re: CUPS Printing - Using a Variable as a Filename (updated)
by haukex (Archbishop) on Aug 20, 2019 at 15:44 UTC
    $printer->printFile($fh, 'jobx')

    The documentation says that printFile wants a filename, not a handle. An in-memory file like this one does not have a filename. You probably want to use File::Temp instead (more examples):

    use File::Temp qw/tempfile/; my ($tfh,$tfn) = tempfile(UNLINK=>1); print $tfh "Some Data...\n"; close $tfh; $printer->printFile($tfn, 'jobx')

    Update: And as I mentioned here, you can use the DIR parameter, and as others have mentioned, you can point that at a RAM disk or similar file system.

Re: CUPS Printing - Using a Variable as a Filename
by holli (Abbot) on Aug 20, 2019 at 16:35 UTC
    the file system will eventually be a read-only one
           - Wayne
    You will have to create a named file
           - Corion
    Anybody remember ram disks? Note, this also uses tmpfs like the /dev/shm solution, but you can control the mount point.


    holli

    You can lead your users to water, but alas, you cannot drown them.
Re: CUPS Printing - Using a Variable as a Filename
by Wayne (Novice) on Aug 20, 2019 at 16:54 UTC

    Thank you for the prompt and informative replies! I knew that there way a way to do it. Perl rocks!

    I have posted the updated code snippit which is now working, below.

    Thanks again!

    #!/usr/bin/perl -t use strict; use warnings; use Net::CUPS::Destination; use File::Temp qw/tempfile/; my ($filehandle,$filename) = tempfile(UNLINK=>1); # Define Printer my $cups = Net::CUPS->new() or die $!; my $printer = $cups->getDestination("CITIZEN-CT-S801") or die $!; open($filehandle, '>', $filename) or die "Cannot open file for writing +: $!\n"; print $filehandle "Some data 1\n"; print $filehandle "Some data 2\n"; print $filehandle "Some data 3\n"; close($filehandle); # Print Data open($filehandle, '<', $filename) or die "Cannot open file for reading +: $!\n"; if ($printer->printFile($filename, 'jobx')) { print 'Success';} else { my $error = $printer->getError(); if ($error) { print "Printer Error: " . $error . "\n"; } } close($filehandle); exit;
      open($filehandle, '>', $filename) or die "Cannot open file for writing +: $!\n"; ... open($filehandle, '<', $filename) or die "Cannot open file for reading +: $!\n"; close($filehandle);

      Note you can remove these lines - tempfile and printFile do this for you. (The first close($filehandle) is still required, but not the second.)