12

Sometimes when I'm working on my laptop, I want to queue up a few documents to print later, since I'm not connected to a printer at the time.

However, actual printer queues are not designed for this; they immediately try to print the document, and all suddenly start printing as soon as I get on the network, which is not generally what I want to do. Moreover, sometimes I want to change the order of documents in the queue, which is not very easy, particularly once some of them have started printing.

Also, sometimes printing fails because e.g. the printer runs out of paper or toner, and I want to re-print the document to a different printer. This is not straightforward with e.g. CUPS or system-config-printer; I generally have to go back, re-open the PDF reader, and start over again. None of the PDF readers I know let you keep a list of documents to print later, but this might be a hidden feature of a PDF reader somewhere that I don't know about.

Anyway, here's what I want to be able to do:

  • Specify a list of PDFs I want to print.
  • Keep that list on disk so that I can close the application or reboot without losing the entire list.
  • Specify the printer(s) I want to send them to in advance without being actually connected to those printers at the time.
  • Specify printing options like color, duplex, and number of copies.
  • Change those printer assignments and print options later.
  • Wait until I press a button or run a command to actually print the document(s).
  • Keep a separate list of documents that have already been printed, in case the printing doesn't work or I want to reprint them later.

I know I could hack something together with a shell script, lpr, and a list of paths in a text file, but I can't help feeling that this problem has already been solved in a more robust and elegant way.

Bonus points:

  • Don't require that the documents be open in a PDF reader. I want to print them, not browse them, and there's no reason they have to be the same application.
  • More than one list.
  • Also work for Postscript, DjVu, and other page-description formats.
  • Drag and drop from file managers.

Any suggestions?

  • Start a bounty if you have enough reputation ;) – A.B. Jul 14 '15 at 8:32
  • As far as I can see, this would require only a simple modification of the printer queues as currently implemented by cups. You would simply print to the desired printer queue, but put the printer jobs "on hold" until you decide to "release" them. The "on hold" button is all that is needed. Or do I miss something? – Jos Jul 14 '15 at 8:52
  • @Jos My version of system-config-printer-applet does allow me to hold and release print jobs as well as move them to other printers, but I can't change the order of print jobs or change the printing options after submitting the job. Also, by that point the path to the original document is long gone. – Nathaniel M. Beaver Jul 14 '15 at 17:18
  • @A.B. Unfortunately bounties require 75 internet points, and I am a lowly 53-pointer. – Nathaniel M. Beaver Jul 20 '15 at 20:45
10

What I do is the following --- it is not as versatile as you asked, but it works almost ok. You need to have all your printers defined, and then you need these two scripts:

  1. stop_printers:

    #!/bin/bash -f
    #
    allp=(`cat /etc/printcap | tr "|" "\t" | cut -f 1 | grep -v "#"`)
    for i in ${allp[@]}; do 
        echo -n Printer $i:
        cupsdisable "$i"
        echo " " paused.
    done
    
  2. start_printers:

    #!/bin/bash -f
    #
    allp=(`cat /etc/printcap | tr "|" "\t" | cut -f 1 | grep -v "#"`)
    for i in ${allp[@]}; do 
        echo -n Printer $i:
        cupsenable "$i"
        echo " " restarted.
    done
    

You have to put them in your path (for example ~/bin) and make them executable with chmod +x. CAVEAT: I do not have any printer with spaces in their names. The scripts are not tested in that case (but I am sure that one of our shell script's gurus will fix the scripts in a flash ;-)... )

Now, you can issue:

[romano:~] % stop_printers
Printer PDF:  paused.
Printer ColorDEA:  paused.
Printer Deskjet_6980:  paused.
Printer fotocop5:  paused.

And you can print from wherever you want, the printer will be paused:

printer from evince

You can see your queue:

[romano:~] % lpq -PDeskjet_6980
Deskjet_6980 is not ready
Rank    Owner   Job     File(s)                         Total Size
1st     romano  439     Bones_3+RG.pdf — Flesh depth  125952 bytes

(AFAIK, the print queues are persistent across reboots). And when you want to print:

[romano:~] % start_printers         
Printer PDF:  restarted.
Printer ColorDEA:  restarted.
Printer Deskjet_6980:  restarted.
Printer fotocop5:  restarted.

Using lprm you can remove a job if you need to; lpr to enqueue a document via command line, and if you want different "lists", no one forbids defining the same printer several times with different names.

You can also resume each printer by hand, it's just a matter of running cupsenable <printername> from the prompt.

What I do not think you can do with this solution is changing the print options after the fact --- you will have to dequeue and re-enqueue the document for this.

  • 2
    +1 Good, however, while you may have your reasons, populating your array could be made simpler by using the proper delimiter in the cut portion: cat /etc/printcap | cut -d "|" -f 1 | grep -v "#" . You save yourself some cycle time by getting rid of the translation tr. This works provided you only need your first field. – Cbhihe Jul 15 '15 at 7:53
1

My package (shameless plug), duplexpr does some of what you want and includes bash functions which may be useful in rolling your own version. (It's coded in bash, so it should be relatively easy to modify and I will help if I can.)

It's designed to emulate duplex printing on non-duplex printers and implements its own simple print queue management. It has both gui and cli interfaces.

The current version only prints in duplex and only works with non-duplex printers, but a new version is in the works which will handle printers with duplex hardware which essentially is just printer and queue management without the duplex emulation software. (I have an alpha version available of a script which already works if anyone wants to contact me directly via the project, etc..)

The system prints to the current default printer, but the dplx and duplex scripts accept additional arguments which are passed to lp and can be used to set any options that lp understands such as printer and other properties.

The system currently handles PDF, PostScript, and plain text files.

The one thing it will not do is print files which were created using the Print to File option from within Acroread. Those files just don't work with lp and I have never been able to get the attention of any of the upstream folks to figure out what the problems are.

Personally, I print almost everything "offline" (using the Print to File options which most applications support) even when my printer(s) are available. It helps me concentrate on what I am doing. Later, when I reach a suitable break point, I print batches of jobs.

Having a print queue is also really nice when you want to print another copy of something without having to regenerate it and it's essential for dealing with printer errors like jams or running out of toner.

  • That is an interesting package, but looks like it has a few rough edges right now, and I'm not sure I'd be able to fix it if something went wrong. By the way, have you considered uploading it to Github? – Nathaniel M. Beaver Aug 12 '15 at 1:09
  • @bariumbitmap - I've been using it daily for over 10 years (since I first wrote it). It's stable. I also have a new version in development. If you break it or need additional features and are willing to work with me, I'll fix it. I have yet to learn git, so I make minimal use of github. Sourceforge is very well known. – Joe Aug 12 '15 at 3:00
0

There doesn't seem to be a complete solution for this problem, but here's a function I added to my .bashrc that is similar to Rmano's answer above, with the additional convenience of autocomplete.

all-printers() {
    if [ "$*" = "" ]
    then
        # Print usage."
        printf "Usage:\n"
        printf "all-printers start\n"
        printf "all-printers stop\n"
        return 1
    elif ! [ "$1" = "stop" -o "$1" = "start" ]
    then
        printf "Unrecognized command: $1\n"
        return 1
    fi

    cut -f 1 -d '|' /etc/printcap |
    grep -v '^#' |
    while read printer_name
    do 
        if [ "$1" = "stop" ]
        then
            cupsdisable "$printer_name"
            printf "$printer_name stopped.\n"
        elif [ "$1" = "start" ]
        then
            cupsenable "$printer_name"
            printf "$printer_name started.\n"
        fi
    done
}
complete -W 'stop start' all-printers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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