Search code examples
linuxbashfindxargsenscript

Convert all files of a specified extension within a directory to pdf, recursively for all sub-directories


I'm using the following code (from this answer) to convert all CPP files in the current directory to a file named code.pdf and it works well:

find . -name "*.cpp" -print0 | xargs -0 enscript -Ecpp -MLetter -fCourier8 -o - | ps2pdf - code.pdf

I would like to improve this script to:

  1. Make it a .sh file that can take an argument specifying the extension instead of having it hardcoded to CPP;

  2. Have it run recursively, visiting all subdirectories of the current directory;

  3. For each subdirectory encountered, convert all files of the specified extension to a single PDF that is named $NameOfDirectory$.PDF and is placed in that subdirectory;


Solution

  • First, if I understand it correctly, this requirement:

    For each subdirectory encountered, convert all files of the specified extension to a single PDF that is named $NameOfDirectory$.PDF

    is unwise. If that means, say, a/b/c/*.cpp gets enscripted to ./c.pdf, then you're screwed if you also have a/d/x/c/*.cpp, since both directories' contents map to the same PDF. It also means that *.cpp (i.e. CPP files in the current dir) gets enscripted to a file named ./..pdf.

    Something like this, which names the PDF according to the desired extension and places it in each subdirectory alongside its source files, doesn't have those problems:

    #!/usr/bin/env bash
    # USAGE: ext2pdf [<ext> [<root_dir>]]
    # DEFAULTS: <ext> = cpp
    #           <root_dir> = .
    ext="${1:-cpp}"
    rootdir="${2:-.}"
    
    shopt -s nullglob
    
    find "$rootdir" -type d | while read d; do
    
      # With "nullglob", this loop only runs if any $d/*.$ext files exist
      for f in "$d"/*.${ext}; do
    
        out="$d/$ext".pdf
        # NOTE: Uncomment the following line instead if you want to risk name collisions
        #out="${rootdir}/$(basename "$d")".pdf
    
        enscript -Ecpp -MLetter -fCourier8 -o - "$d"/*.${ext} | ps2pdf - "$out"
    
        break   # We only want this to run once
    
      done
    
    done