Print many files on a Mac

with a single one-liner command

Posted by paul on 2017.05.18

Using Mac to print multiple text files quickly from Terminal

On my Mac, I wanted to print out a few text files (ex: all that match ex1*.py) of Python code to review. Opening each file to print would be no fun. So I looked around to see how to print files using command line in Terminal on a Mac.

Following is a one-liner I put together to accomplish the task, using for-loop, find, ld, vim, and rm. You can run the command just once and it will print all files that match ex1*.py in the current directory. To examine the command better, you can copy/paste the command into a text editor like Atom.

for i in `find . -name "ex1*.py"`; do i=`basename $i .py` && vim -c "hardcopy > $i.ps" -c quit $i.py && lp -d CanonMF $i.ps && rm -f $i.ps; done

When used in a shell script file, it would look like below:

#!/bin/bash
for i in `find . -name "ex1*.py"`
do
    i=`basename $i .py`
    vim -c "hardcopy > $i.ps" -c quit $i.py
    lp -d CanonMF $i.ps
    rm -f $i.ps
done

I will break down the command below.

On Mac, print using lp command in Terminal

On a Mac, you can print a text file (or source code files such as .html or .py) from Terminal using "lp" command. But to use lp command, you have to know the name of the printer that your Mac uses.

To find the printer name to use with lp command on your Mac, do following.

  1. Go to System Preferences
  2. Go to Printers & Scanners
  3. Click to highlight the printer you want to print to.
  4. Click on Options & Queues.
  5. Copy the value of Device Name. Below is what is on my Mac, so I'd use CanonMF
  6. Device Name: CanonMF

The command to print file ex01.py from Terminal would be something like below.

lp -d CanonMF ex01.py

In your Terminal, you have to make sure your current directory is where the file ex01.py is in. Using "cd" command, change your present directory to where the file is in.

Create PostScript file with vim

The formatting of the printout is ugly. To print from Terminal with better formatting, you can use vim to create PostScript file of a file, and that PostScript file is then sent to the printer. Below, vim is used to create a file ex01.ps (aka PostScript file) from file ex01.py.

vim -c "hardcopy > ex01.ps" -c quit ex01.py

Let's examine the command above. All of the text above should be used exactly as shown, except for following 2:

  1. ex01.ps
  2. ex01.py

Note ex01.ps is the name of the PostScript file that vim is creating. You can use any file name (like print.ps or 1.ps) instead of ex01.ps. And ex01.py is of course the source code file you want to print on paper.

Sending the PostScript file to printer

Once you have the PostScript file, you will then send the PostScript file, ex01.ps, to your printer.

lp -d CanonMF ex01.ps

Note ex01.ps is the newly created PostScript file that was created with vim command.

Put vim and lp commands together to actually print from your printer

We need to combine vim and lp together.

vim -c "hardcopy > ex01.ps" -c quit ex01.py && lp -d CanonMF ex01.ps

In plain English, this is what's happening.

  • vim opens ex01.py file, and creates PostScript file, ex01.ps.
  • If, and only if, the vim command is successful, "lp" command will send ex01.ps file to the printer. This logic is because of "&&".
  • Note "&&" is called a logical operator. When you put && between 2 commands in bash, the 2nd command will run ONLY if the 1st command ran successfully.

    Test printing ex01.py again and you should get the printout with much better formatting.

    Optional: Print in landscape, not portrait

    If you are printing SQL commands or other source code that's better viewed in landscape mode, you will need to edit ~/.vimrc. The file ".vimrc" controls formatting and other settings of vim editor.

    To edit .vimrc, do following in Terminal. You probably want to open a new Terminal window on your Mac.

    1. Use vim to create .vimrc.
    2. vim ~/.vimrc
    3. Important to include "~/."
    4. Enter 'edit' mode in vim by hitting "i" (for insert mode).
    5. Type in or paste in following exactly as shown:
    6. set printoptions=portrait:n
    7. Hit "Esc" key to exit edit mode.
    8. Type in following to save .vimrc and close vim editor. w is for write and q is for quit. Here the text you enter will be shown at bottom left of your Terminal.
    9. :wq

    Test printing again and you should get the print out in landscape. Here's the command of vim & lp to print a file using PostScript file.

    vim -c "hardcopy > ex01.ps" -c quit ex01.py && lp -d CanonMF ex01.ps
    

    Print multiple files at once

    So how can you print multiple text files by running a commmand once?

    Let's assume in your directory you have 12 files: ex01.py, ex02.py, ex03.py, ~ ex12.py. And you want to print 3 files: ex10.py, ex11.py and ex12.py. To accomplish this, we will use "for loop".

    We are using the for loop available in bash shell.

    for VARIABLE in 1 2 3
    do
      command1
      command2
    done
    

    Normally, the for loop is used as above with line breaks when it's used in a shell script. However we will use it in a one liner, which means we will use for-loop as shown below. Note the two instances of ";".

    for VARIABLE in 1 2 3; do command1 && command2; done
    

    So here's the final version of the one-liner you can use (run it just once) to print multiple text files from your Mac. The example prints out all files that match "ex1*.py" in your current working directory.

    for i in `find . -name "ex1*.py"`; do i=`basename $i .py` && vim -c "hardcopy > $i.ps" -c quit $i.py && lp -d CanonMF $i.ps && rm -f $i.ps; done
    

    Same command in a shell script for better readability.

    #!/bin/bash
    for i in `find . -name "ex1*.py"`
    do
        i=`basename $i .py`
        vim -c "hardcopy > $i.ps" -c quit $i.py
        lp -d CanonMF $i.ps
        rm -f $i.ps
    done
    

    Details of the final command

    This "for loop" will loop 3 times as the find command will find 3 files: ex10.py, ex11.py and ex12.py.

    for i in `find . -name "ex1*.py"`
    

    First file that will be printed is ex10.py. Below changes the value of variable i from ex10.py to ex10.

    i=`basename $i .py`
    

    Create a PostScript file for each ex1*.py file. So vim will generate ex10.ps, from ex10.py.

    vim -c "hardcopy > $i.ps" -c quit $i.py
    

    Send the PostScript ex10.ps to the printer.

    lp -d CanonMF $i.ps
    

    Delete the PostScript file ex10.ps as it is not needed anymore.

    rm -f $i.ps
    

    Summary: Once ex10.py is printed, for-loop will loop around and go through the same process and print ex11.py. When done with ex11.py, it will print ex12. Once that's done, the command is done.

    That's it. Hopefully you learned something new today. Please remember to conserve paper.