I would like to add a 'virtual' printer to easily send PDF output from any software. The printer should be a script which then processes the PDF output. Use-case could be "print to cloud storage" or "print to archive" etc.

The possiblities I discovered so far are:

  • CUPS pipe backend (described here) which seems to be not available on Ubuntu.
  • tea4cups (from this thread) which forwards the file to lp after pre-processing it. But I do not want to actually print it.

Is there another simpler way to just get the PDF piped into a custom bash script?

up vote 5 down vote accepted
+50

The clues appear to be in the first link in your question. Research indicates that backends are just scripts. So you could simply write your own. However it appears that the script you are looking for that's available for OpenSuse is described in your first link.

The openSUSE RPM package cups-backends provides the bash script /usr/lib/cups/backend/pipe which is a wrapper backend for printing to any program.

finding this script is complicated by the fact the OpenSuse now uses .ymp one click installers and you have to dig a bit deeper to find the actual .rpm that contains the script. Here's an example taken directly from cups-backends-1.1-296.6.noarch.rpm available here.

Opening the package with file roller and navigating to /./usr/lib/cups/backend/ within the package and opening pipe reveals the script below:

#! /bin/bash
# CUPS wrapper backend "pipe" for printing to any program.
# It forwards the print job data like a pipe into another command.
# Author: Johannes Meixner <jsmeix@suse.de>, 2009, 2014
# For basic information see "man 7 backend" and "man 7 filter".
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU GENERAL PUBLIC LICENSE Version 2
# as published by the Free Software Foundation.

# Activate the "set -x" line to get debugging info in /var/log/cups/error_log:
#set -x

# Output "Device Discovery" information on stdout:
if test "$#" = "0"
then
  echo 'direct pipe "Unknown" "Forward print job data like a pipe to another command"'
  exit 0
fi

# Output usage information in case of wrong number of parameters:
if test "$#" != "5" -a "$#" != "6"
then
  echo 'Usage: pipe job-id user title copies options [file]' 1>&2
  echo 'Queue setup example:' 1>&2
  echo 'lpadmin -p queue_name -v "pipe:/path/to/command?option1=value1&-option2&value2" -E' 1>&2
  echo 'The command is called with the specified options as:' 1>&2
  echo '/path/to/command option1=value1 -option2 value2' 1>&2
  echo 'The original command line parameters (... job-id user ...)' 1>&2
  echo 'are provided as environment variables PIPE_BACKEND_ARGV[0-6]' 1>&2
  exit 1
fi

# Keep the original command line parameters (... job-id user ...)
# in environment variables to make them available for the command:
export PIPE_BACKEND_ARGV0="$0"
export PIPE_BACKEND_ARGV1="$1"
export PIPE_BACKEND_ARGV2="$2"
export PIPE_BACKEND_ARGV3="$3"
export PIPE_BACKEND_ARGV4="$4"
export PIPE_BACKEND_ARGV5="$5"
export PIPE_BACKEND_ARGV6="$6"

# Have the input at fd0 (stdin) in any case:
if test -n "$6"
then
  exec <"$6"
fi

# To be on the safe side clip anything after the first space character
# because spaces are excluded characters in a URI (see RFC 2396):
URI=${DEVICE_URI%% *}
# Extract the command to which the job schould be sent from the URI.
# Clip the URI scheme (anything up to the first ':' character) and
# clip anything after the first '?' character
# because anything after the first '?' character are options:
COMMAND=${URI#*:}
COMMAND=${COMMAND%%\?*}
# Extract the options (e.g. from 'pipe:/path/to/command?option1=value1&-option2&value2'
# clip anything up to the first '?' character and
# replace the options separator '&' character by a space:
OPTIONS=${URI#*\?}
if test "$OPTIONS" = "$URI"
then
  OPTIONS=""
fi
OPTIONS=$( echo "$OPTIONS" | tr '&' ' ' )
# Options could have been specified in a wrong way
# as addendum to the DeviceURI separated by spaces
# (spaces are excluded characters in a URI, see RFC 2396)
# which works by luck at least for some CUPS versions
# see https://bugzilla.novell.com/show_bug.cgi?id=499735
# like 'pipe:/path/to/command option1=value1 -option2 value2'
# nevertheless use additionally those kind of options too:
MORE_OPTIONS=${DEVICE_URI#* }
if test "$MORE_OPTIONS" = "$DEVICE_URI"
then
  MORE_OPTIONS=""
fi
OPTIONS=$( echo "$OPTIONS" "$MORE_OPTIONS" | tr -s ' ' )

# Test if the command is executable:
if ! test -x "$COMMAND"
then
  echo "Cannot execute $COMMAND" 1>&2
  exit 1
fi

# Replace this wrapper with the actual command
# so that it exits with the exit code of the command
# and that the command gets any signals directly.
exec "$COMMAND" $OPTIONS

Since this is a bash script you should be able to use it with any version of 'nix including Ubuntu, with a bash shell, not just Suse.

In order to add a backend to cups you'll need to copy it to /usr/lib/cups/backend and set the permissions and ownership to match.

chown root:root /usr/lib/cups/backend/pipe

chmod 755 /usr/lib/cups/backend/pipe

Sources:

https://www.cups.org/doc/man-backend.html

https://build.opensuse.org/package/view_file/Printing/cups-backends/cups-backends.spec?expand=1

How do I extract a RPM file?

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.