Running options in bash script

Hello UNIX & Linux Forums community! Long time Linux daily user hobbyist, new to shell scripting....

I'm working on a script that does all the "work" in one script, and makes calls to a second script to display info to the user via mostly expanding variables in heredocs.

I'm contemplating a -q --quiet option to stop the info displaying. Being new to this, I've thought through and tested the following.

However, I'm at a loss as to the terminology used for what I'm trying to do. That leaves me at a loss to find out if my method would be considered bad scripting, and if so, what would be a more appropriate method to easily implement a --quiet option.

The scripts are quite tested and working well at this point. This is more of an afterthought and mental exercise than something really needed.

BTW, I'm manually parsing options without using getopts. I could post the scripts, around 300 lines total, if needed. It's a (current version) bash script, running Arch Linux if it matters. (mostly current version prog's)

#!/bin/bash


mainfunc () {
    echo "run mainfunc commands"
    $switch    
}

optfunc () {
    echo "run user info extras"
}



normal () { switch=optfunc
}
quiet () { switch=  
}


while    :; do
    case "${1}" in
        -R)     normal ; mainfunc     ;;
       -Rq)     quiet  ; mainfunc    ;;
         *)    break
    esac
    shift
done

Why aren't you using getopts ? Having consistent methods of parsing options greatly contributes to the ability of users unfamiliar with your code automatically know how to get a quick view of the syntax of your utility (with something like: utility -? ), the ability to specify options separately or combined and in any order:

utility -Rq
utility -qR
utility -R -q
utility -q -R

should all produce the same results. And, you should have a built-in help/usage message if an unknown option is found. Instead, your code silently ignores unknown options (leading users to believe that the options they provided were correct when, instead, nothing will be done by your code).

You generally want to set flags while processing options, not run the functions that the options indicate should be run (after you have determined all of hte options that are present).

Your code seems to indicate that the -R option in your utility must always be present. Why have an option if it is always required to be set?

1 Like

I can think of two methods of implementing a quiet mode. First, use redirections.

if [ "${quietmode}" = "yes" ]
then 
   exec >/dev/null
fi
printf "this will not be printed in quiet mode\n"
printf "this is a required message and will be printed\n" > /dev/tty

Alternatively:

if [ "${quietmode}" = "yes" ]
then
   exec 3>/dev/null
else
   exec 3>&1
fi
printf "This won't be printed in quiet mode\n" >&3
printf "This will always be printed\n"

The other way is to use a function:

function myprint() {
   local mode=$1
   shift
   if [ "${mode}" = normal ] && [ "${quietmode}" = "yes" ]
   then
      return
   fi
   printf "$@"
}

myprint normal "this will not be printed in quiet mode\n"
myprint quiet "this will be printed always\n"

Untested.

Andrew

1 Like

Thanks for replies.

Second time someone asked why not using getopts. I have not looked into it so far, although I probably should.

With manually parsing options, I consider each argument as an operation rather than an option. No real option ability...

When the program is called with no operations, or a non existent op, they get this or in the former, without the error message.:

$ aurt -qR

  Input Error: Please try again or see    aurt --help

 |=====================================================================================|
 |    Aurt, a tiny AUR helper script.         USAGE:  $ aurt [operation] [package]     |
 |-------------------------------------------------------------------------------------|
 | -S  Install Update                -F  Files Provided By Pkg          NOTES:         |
 | -Sv Update By Version             -s  Search For Pkg                                |
 | -Sf Force Install Update          -p  Pacman Log                                    |
 | -R  Remove Pkg And Bld Dir        -h  Help                      leafpad-aurt: lat   |
 | -C  Ck All Pkgs For Updates                                  thunar-base dir: tbd   |
 | -D  Package Dependency Details                              Orphans:  R $(p -Qtdq)  |
 |=====================================================================================|

The scripts:

https:bbs.archlinux.org/viewtopic.php?id=232437

I was contemplating using the --quiet "option" with the -S and -Sv operations only, as the rest couldn't use --quiet.

I read getopts will not take long options? My script needs the ability to process package names, ie: aurt -S <package name> That and manually parsing them seemed more straight forward to me when I started, likely because of my inexperience.

At this point, it sounds like I need to get my head around understanding getopts and figure out how to deal with the program names separately?

Just reading the replies from you guys gives my more things to research, test, and think about.

getopt does not prevent you from getting package names. That's not what "long options" means also, long options means double-dash-word options like --quiet.

In addition to what Corona688 already said (although I think he meant getopts instead of getopt ), in your example:

aurt -S <package name>

<package name> is either a -S option option-argument or an aurt operand; not an option. You haven't given us enough information to know which you intended in your example. The getopts utility does not place any length limit on option-argument nor operand strings.

Furthermore with many versions of the Korn shell, the built-in getopts utility can handle long and short options (although some ksh man pages fail to document this feature). The method ksh uses doesn't work on bash version 3.2.57. I don't know if it works on bash 4.x version and, you haven't said what version of bash you're using.

To investigate this further, check the thread ksh parsing arguments in a string rather than from the cmdln.

Hi.

There are many schemes / methods / alternatives to help process command line -- CLI -- options. Here are a few. Some take a bit of effort to learn, but they will be time-savers in future work.

I especially like the ones that create man-like pages, and help displays automatically ... cheers, drl

Process command-line (CLI) options, arguments

        1) getopts, builtin, bash, ksh, zsh
           http://stackoverflow.com/questions/402377/using-getopts-in-bash-shell-script-to-get-long-and-short-command-line-options
           Also, search for option processing, including:
           http://mywiki.wooledge.org/ComplexOptionParsing

        2) perl: many, including libgetopt-euclid-perl, which
           creates man page, help automatically

        3) getopt, enhanced getopts, part of the util-linux, allows GNU "--"
           Examples: /usr/share/doc/util-linux/examples, 2016.03.27

        4) argp.sh, wrapper for getopt, creates man and help (text, XML), etc.
           Allows mixed options and arguments.
           Compiled argp.c -> argp for faster execution.
           https://sourceforge.net/projects/argpsh/, 2016.03.27

        5) shflags, wrapper for getopt, creates help, allow mixed options
           and arguments
           https://github.com/kward/shflags, 2016.08.01

        6) ksh getopts, enhanced, process GNU "--", creates man, help, etc.
           Examples: Learning the Korn Shell, O'Reilly, 2nd, p 380ff

        7) zsh zparseopts
           man zshmodules, part of zshutil

        8) Suggested option names:
           http://www.shelldorado.com/goodcoding/cmdargs.html#flagnames