202 lines
6.5 KiB
Bash
Executable File
202 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
### FUNCTIONALITY ###
|
|
# Compress PDF files via Ghostscript in the folder where this script resides
|
|
# 1. Create a sub-folder, ./compressed, and put the resultant compressed ones in it,
|
|
# 2. Compress files with any PDF extensions i.e., .pdf, .PDF, .pDf and so on,
|
|
# 3. Optional compression parameter to be supplied, namely, prepress, ebook (default) and screen - in the descending order of quality,
|
|
# 4. Log output with the compressed file names and any error message in the sub-folder, and
|
|
# N.B. Make sure to make this script executable via chmod +x or 755, after copying!
|
|
|
|
shopt -s nocaseglob
|
|
# Bash matches filenames in a case-insensitive fashion when performing filename expansion
|
|
# E.g., a.pdf, b.PDF and c.PdF all gets compressed
|
|
|
|
set -eo pipefail
|
|
# e: The script will exit on an error
|
|
# u: <ABORTED> Treat unset variables as an error when performing parameter expansion
|
|
# This gives an error, "$1: unbound variable", when taking in input parameter of a command
|
|
# o pipefail: If any element of the pipeline fails, then the pipeline as a whole will fail
|
|
# This is dangerous as pipelines only return a failure if the last command errors by default
|
|
|
|
# All variables in bash are global by default
|
|
# Global variables should be in ALL_CAPITAL_CASE with readonly designation
|
|
# Variable substitution within a sting should be "${variable}", NOT just $variable
|
|
# Use POSIX-compliant [[ ]], i.e., ksh, zsh, etc., rather than []
|
|
# REFERENCE: https://google.github.io/styleguide/shellguide.html
|
|
|
|
show_no_setting_msg() {
|
|
echo "No compression setting specified!"
|
|
}
|
|
|
|
show_setting_not_recognised_msg() {
|
|
echo "Setting not recognised!"
|
|
}
|
|
|
|
show_ghostscript_not_installed_msg() {
|
|
echo "Ghostcript not installed!"
|
|
}
|
|
|
|
show_help_msg() {
|
|
local help_msg
|
|
|
|
help_msg="
|
|
NAME
|
|
Compress all the PDF files in the same folder as this script resides via
|
|
Ghostscript and put them into a newly created \"compressed\" sub-folder
|
|
SYNOPSIS
|
|
pdf_batch_compressor.sh [OPTION]
|
|
DESCRIPTION
|
|
-s, --setting=SETTING
|
|
override default ebook; prepress, ebook or screen (in the descending order of quality)
|
|
-h, --help
|
|
display this help and exit
|
|
"
|
|
|
|
# echo $help_msg (without quotes) does NOT retain the new lines!
|
|
# After expanding, the enclosing double quotes stops
|
|
# '(field) splitting (via $IFS) and globbing(i.e., pathname expansion))'
|
|
echo "${help_msg}"
|
|
}
|
|
|
|
#######################################
|
|
# Remove a number of characters from a string from the beginning
|
|
# Arguments:
|
|
# A string
|
|
# An integer
|
|
# Returns:
|
|
# A trucated string
|
|
# Example:
|
|
# truncate_char_from_beginning abcde 2 => cde
|
|
#######################################
|
|
truncate_char_from_beginning() {
|
|
# shellcheck disable=SC2005
|
|
echo "$(echo "$1" | cut -c $(($2+1))-)"
|
|
}
|
|
|
|
#######################################
|
|
# Make sure legit input parameters
|
|
# Arguments:
|
|
# An optional setting parameter
|
|
# Returns:
|
|
# None. Call Ghostscript function
|
|
#######################################
|
|
check_inputs() {
|
|
#`declare` stipulates a variable as "local" by default. `-r` makes it readonly
|
|
declare -r SHORT_SETTING_SWITCH=-s=
|
|
declare -r LONG_SETTING_SWITCH=--setting=
|
|
|
|
local compression_setting
|
|
local ghostscript_dir_and_exec
|
|
|
|
local short_setting_switch_len
|
|
local long_setting_switch_len
|
|
|
|
# `-n` truncates the trailling new-line character
|
|
short_setting_switch_len=$(echo -n "$SHORT_SETTING_SWITCH" | wc -m)
|
|
long_setting_switch_len=$(echo -n "$LONG_SETTING_SWITCH" | wc -m)
|
|
|
|
while [[ "$1" != "" ]]; do
|
|
case $1 in
|
|
-h | --help)
|
|
show_help_msg
|
|
exit 1
|
|
;;
|
|
*)
|
|
if [[ $(echo "$1" | head -c "$short_setting_switch_len") = "$SHORT_SETTING_SWITCH" ]]; then
|
|
compression_setting=$(truncate_char_from_beginning "$1" "$short_setting_switch_len")
|
|
elif [[ $(echo "$1" | head -c "$long_setting_switch_len") = "$LONG_SETTING_SWITCH" ]]; then
|
|
compression_setting=$(truncate_char_from_beginning "$1" "$long_setting_switch_len")
|
|
else
|
|
# Unrecognisable input parameter
|
|
show_help_msg
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [[ -z "${compression_setting}" ]]; then
|
|
# True if not set i.e., the length of the tested is zero
|
|
compression_setting=ebook
|
|
fi
|
|
|
|
ghostscript_dir_and_exec=$(command -v gs)
|
|
|
|
if [[ -z "${ghostscript_dir_and_exec}" ]]; then
|
|
show_ghostscript_not_installed_msg
|
|
exit 1
|
|
else
|
|
case "${compression_setting}" in
|
|
prepress | ebook | screen)
|
|
;;
|
|
*)
|
|
show_setting_not_recognised_msg
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
compress_pdf "${compression_setting}" "${ghostscript_dir_and_exec}"
|
|
}
|
|
|
|
#######################################
|
|
# Called from the bottom of this script. Call Ghostscript command
|
|
# Arguments:
|
|
# Compression setting
|
|
# Ghostscript binary file location in an absolute path
|
|
# Returns:
|
|
# None
|
|
#######################################
|
|
compress_pdf() {
|
|
#`declare` stipulates a variable as "local" by default. `-r` makes it readonly
|
|
declare -r SUBDIR_NAME=compressed
|
|
|
|
local compression_setting
|
|
local ghostscript_dir_and_exec
|
|
local subdir_path
|
|
local log_filename_in_full_path
|
|
local filename_only
|
|
|
|
# Output is without the trailing directory separator, so add "/" at the end
|
|
dir_path=$(pwd)/
|
|
|
|
compression_setting=$1
|
|
ghostscript_dir_and_exec=$2
|
|
|
|
subdir_path="${dir_path}/${SUBDIR_NAME}/"
|
|
|
|
# `-f` silently ignores non-existent file(s) to avoid "rm: cannot remove '': No such file or directory"
|
|
rm -rf "${subdir_path}"
|
|
mkdir "${subdir_path}"
|
|
|
|
# Use this script name as part of log file name
|
|
log_filename_in_full_path="${subdir_path}""$(basename "$0")".log
|
|
|
|
for filename_in_full_path in "${dir_path}"/*.pdf; do
|
|
filename_only=$(basename "${filename_in_full_path}")
|
|
|
|
echo "${filename_only}" >> "${log_filename_in_full_path}"
|
|
|
|
# (command) runs in a subshell
|
|
# `&>> file` appends stderr and stdout to file
|
|
# source: https://ops.tips/gists/redirect-all-outputs-of-a-bash-script-to-a-file/
|
|
(
|
|
"${ghostscript_dir_and_exec}" -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 \
|
|
-dPDFSETTINGS=/"${compression_setting}" -dNOPAUSE -dQUIET -dBATCH \
|
|
-sOutputFile="${subdir_path}${filename_only}" "${filename_in_full_path}"
|
|
) &>> "${log_filename_in_full_path}"
|
|
done
|
|
}
|
|
|
|
# https://nenadsprojects.wordpress.com/2012/12/27/bash_source/
|
|
#
|
|
# Sourced Not-Sourced
|
|
# ${BASH_SOURCE[0]} this.sh this.sh
|
|
# ${BASH_SOURCE[1]} sourcing.sh
|
|
# $0 sourcing.sh this.sh
|
|
if [[ ${BASH_SOURCE[0]} == "$0" ]]; then
|
|
# Not sourced from anywhere else
|
|
check_inputs "$@"
|
|
fi |