#!/bin/bash # # fbopt version 0.4.1 # # Written in 2018 by Franco Masotti/frnmst # # To the extent possible under law, the author(s) have dedicated all # copyright and related and neighboring rights to this software to the public # domain worldwide. This software is distributed without any warranty. # # You should have received a copy of the CC0 Public Domain Dedication along # with this software. If not, see # . # # # See also https://frnmst.gitlab.io/notes/my-bash-option-parsing-template.html # show_help() { cat <<-EOF Usage: spectrscan [OPTION] OUTFILE An unintrusive frontend of scanimage which acts as a paper to pdf converter suitable for texts. If the ouput file exists then the new scanned documents will be added as the tail of the existing one. The default system scanner is used. Mandatory arguments to long options are mandatory for short options too. Options: -h, --help print this help -i, --imagemagick=OPTIONS pass options to ImageMagick to post-process the documents --list-modes list all possible scan modes --list-resolutions list all possible resolutions --list-sources list all possible sources -m, --mode=MODE scan in Color, Lineart, Gray or whatever supported method --print-flags print the enabled options. This can also be used to print the default options -r, --resolution=RESOLUTION page resolution in DPI -s, --source=SOURCE scan from the ADF, Flatbed or whatever supported method -t, --two-sided toggle preserve the order in double sided paper: scan a batch of papers one side, then the other --two-sided-reverse same as '--two-sided' but with the need of reversing every single paper. This option conflicts with '--two-sided' -u, --unpaper[=OPTIONS] enable unpaper. You may pass options to unpaper Exit status: 0 if OK, 1 if an error occurred. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. License GPLv3+: GNU GPL version 3 or later . Copyright © 2017 Franco Masotti. EOF } # A function that prints the variable name and value of all # the flags enabled by the user. This is useful to check that # all the flags are correct, as kind of a dry run. show_flags() { local flags="${*}" for flag in ${flags}; do printf "%s='%s'\n" "${flag}" "${!flag}" done } getopt_error() { local program_name="${0}" printf "%s\n" "Try '"${program_name}" --help' for more information" } 1>&2 2>&- main() { # Create a new array from the reference of the input one. # See https://stackoverflow.com/questions/1063347/passing-arrays-as-parameters-in-bash # See some comments below. declare -a argc=("${!1}") local getopt_short_options='hi:m:r:s:tu::' local getopt_long_options='help,imagemagick:,list-modes,list-resolutions,list-sources,mode:,print-flags,resolution:,source:,two-sided,two-sided-reverse,unpaper::' # Set the default values for the flags. local imagemagick="${IMAGEMAGICK}" local mode="${MODE}" local resolution="${RESOLUTION}" local source="${SOURCE}" local unpaper="${UNPAPER}" local two_sided="${TWO_SIDED}" local program_name="${0}" opts="$(getopt \ --name "${program_name}" \ --shell bash \ --options "${getopt_short_options}" \ --longoptions "${getopt_long_options}" \ -- \ "${argc[@]}")" getopt_retval=${?} # Check that getopt works and that some kind of argument # is passed to the script. This is "quotation hell". a="'"${argc[@]}"'" { [ ${getopt_retval} -ne 0 ] || [ -z "${a}" ]; } && getopt_error && return 1 eval set -- "${opts}" # Option parsing. while [ "${1}" != '--' ]; do case "${1}" in -h | --help ) help='true' ;; -i | --imagemagick ) imagemagick="${2}"; shift 1 ;; --list-modes ) list_modes='true' ;; --list-sources ) list_sources='true' ;; --list-resolutions ) list_resolutions='true' ;; -m | --mode ) mode="${2}"; shift 1 ;; --print-flags ) print_flags='true' ;; -r | --resolution ) resolution="${2}"; shift 1 ;; -s | --source ) source="${2}"; shift 1 ;; -t | --two-sided ) two_sided='true' ;; --two-sided-reverse ) two_sided_reverse='true' ;; -u | --unpaper ) unpaper="${2}"; shift 1 ;; esac # Iterate through all arguments. shift 1 done shift 1 # Everything else after '--' is an argument. argc="${*}" # Override values of optional parameters. # This must be done before showing the flags. [ -z "${unpaper}" ] && unpaper='true' # Check that the flags that must be non empty are actually not empty. # A user might infact circumvent getopt's mechanisms like this # ./program -flag '' # This can also be done inside the option parser loop but to avoid nestings # I prefer it done here. { [ -z "${imagemagick}" ] \ || [ -z "${mode}" ] \ || [ -z "${resolution}" ] \ || [ -z "${source}" ]; } \ && getopt_error && return 1 [ "${print_flags}" = 'true' ] \ && show_flags \ 'imagemagick' \ 'mode' \ 'list_modes' \ 'resolution' \ 'list_resolutions' \ 'source' \ 'list_sources' \ 'two_sided' \ 'two_sided_reverse' \ 'unpaper' \ && return 0 [ "${help}" = 'true' ] && show_help && return 0 # From now on you should call a function or an external program # using the values of the flag variables. [ "${two_sided}" = 'true' ] \ && [ "${two_sided_reverse}" = 'true' ] \ && getopt_error \ && return 1 [ "${list_modes}" = 'true' ] \ && supported_params="$(get_supported_parameters)" \ && get_supported_modes \ && return ${?} [ "${list_resolutions}" = 'true' ] \ && supported_params="$(get_supported_parameters)" \ && get_supported_resolutions \ && return ${?} [ "${list_sources}" = 'true' ] \ && supported_params="$(get_supported_parameters)" \ && get_supported_sources \ && return ${?} # Override two_sided value if necessary. [ "${two_sided_reverse}" = 'true' ] && two_sided='reverse' local output_file="${1}" [ -z "${output_file}" ] && getopt_error && return 1 preliminary_checks \ "${imagemagick}" \ "${mode}" \ "${resolution}" \ "${source}" \ "${unpaper}" \ "${two_sided}" \ "${output_file}" } # Test dependencies and versions. # getopt must return 4 to be fully compatible. See getopt's manual. which bash getopt 1>/dev/null 2>/dev/null && { getopt -T; [ ${?} -eq 4 ]; } # Get and pass argc to the main function. # All this work with an array must be done to preserve # quotations for arguments that have whitespaces. # See https://lists.debian.org/debian-user/2007/12/msg01244.html declare -a opts=() for opt in "${@}"; do opts=("${opts[@]}" "${opt}") done main 'opts[@]'