book
  • README
  • cheatsheet
    • bash
      • builtin
      • syntactic sugar
      • cmd
      • havefun
    • text-processing
      • awk
      • sed
      • html
      • json
      • regex
      • unicode
    • osx
    • curl
    • tricky
    • widget
    • proxy
    • colors
    • math
    • media
    • ssl
      • keystore
      • verification
      • server
      • client
      • tricky
    • windows
      • powershell
      • choco
      • wsl
      • wt
      • shortcut
      • clsid
      • env
      • shell:folder
  • vim
    • nvim
    • install
    • color
    • plugins
      • usage
      • other plugins
      • deprecated
    • tricky
    • viml
    • windows
    • troubleshooting
  • devops
    • admin tools
    • ssh
    • git
      • config
      • alias
      • submodule
      • eol
      • example
      • gerrit
        • gerrit API
      • github
      • troubleshooting
      • tricky
      • statistics
    • pre-commit
    • release-tools
    • tmux
      • cheatsheet
    • ansible
    • vault
    • artifactory
      • api
      • cli
      • aql
      • nginx cert
    • klocwork
      • kwadmin
      • kwserver
      • api
      • q&a
    • elk
    • mongodb
    • android
    • mobile
  • jenkins
    • config
      • windows
    • appearance
    • troubleshooting
    • jenkinsfile
      • utility
      • parallel
      • build
      • envvar
      • properties
      • trigger
      • node
    • script
      • job
      • build
      • stage
      • agent
      • security & authorization
      • exception
      • monitor
      • tricky
    • api
      • blueocean
    • cli
    • plugins
      • kubernetes
      • docker
      • shared-libs
      • lockable-resource
      • ansicolor
      • badge
      • groovy-postbuild
      • simple-theme
      • customizable-header
      • artifactory
      • jira-steps
      • job-dsl
      • build-timeline
      • crumbIssuer
      • coverage
      • uno-choice
      • tricky
  • virtualization
    • kubernetes
      • init
        • kubespray
        • kubeadm
          • environment
          • crio v1.30.4
          • docker v1.15.3
          • HA
        • addons
        • etcd
      • kubectl
        • pod
        • deploy
        • replicasets
        • namespace
        • secrets
      • node
      • certificates
      • events
      • kubeconfig
      • kubelet
      • troubleshooting
      • cheatsheet
      • auth
      • api
      • tools
        • monitor
        • helm
        • network
        • minikube
    • docker
      • run & exec
      • voume
      • remove
      • show info
      • dockerfile
      • dockerd
      • tricky
      • troubleshooting
      • windows
    • crio
    • podman
  • ai
    • prompt
  • osx
    • apps
      • init
      • brew
    • defaults
    • system
    • network
    • script
    • tricky
  • linux
    • devenv
    • util
      • time & date
      • output formatting
      • params
      • tricky
    • nutshell
    • disk
    • network
    • troubleshooting
    • system
      • apt/yum/snap
      • authorization
      • apps
      • x11
    • ubuntu
      • systemctl
      • x
    • rpi
  • programming
    • groovy
    • python
      • config
      • basic
      • list
      • pip
      • q&a
    • others
    • archive
      • angular
      • maven
      • mysql
        • installation
        • logs
      • ruby
        • rubyInstallationQ&A
  • tools
    • fonts
    • html & css
    • Jira & Confluence
    • node & npm
      • gitbook
      • hexo
      • github.page
      • code themes
    • app
      • microsoft office
      • vscode
      • virtualbox
      • iterm2
      • browser
      • skype
      • teamviewer
      • others
  • quotes
  • english
Powered by GitBook
On this page
  • shell parameter parsers
  • pass parameters to another script
  • Manual Case-Loop Parser
  • POSIX getopts Parser
  • GNU getopt Parser
  • bash-argparse Library
  • docopts
  • argbash Code Generator
  • shflags (Google-style shell option lib)
  • references

Was this helpful?

  1. linux
  2. util

params

Previousoutput formattingNexttricky

Last updated 1 month ago

Was this helpful?

[!TIP|label:see also:]

shell parameter parsers

PARSER STYLE
DESCRIPTION
PROS
CONS
PORTABILITY

🔸 case + shift loop

Manual parsing with a while + case combo

- Highly customizable - Simple

- Error-prone for complex flags - No automatic help

✅ POSIX-compliant

🔸 getopts (built-in)

Built-in short-option parser

- Easy for short options (-x)

- No long options - No auto help

✅ POSIX-compliant

🔹 getopt (external)

External tool to parse long/short flags

- Supports long & short - Auto reordering

- Not always installed - Not portable across BSD/Linux

⚠️ Not portable

🔸 bash-argparse (lib)

Bash-based helper library

- Structured, powerful - Python-like syntax

- Adds dependency - Not always installed

❌ Bash-only

🔹 docopts (doc-style)

Parses from usage doc string

- Clean UX - Declarative

- Heavy - Requires Python or external

❌ External

🔸 argbash (codegen)

Generates parsing boilerplate

- Auto docs/help - Safe/robust

- Needs build step

❌ Not runtime native

🔹 shflags (Google)

Lightweight Bash lib

- Google-style - Nice syntax

- Needs sourcing a lib

⚠️ Bash-only

PARSER
SHORT OPTS
LONG OPTS
PORTABLE
HELP GEN
EXTERNAL?

Manual Case

✅

✅ (manual)

✅ POSIX

❌

❌

getopts

✅

❌

✅ POSIX

❌

❌

getopt

✅

✅

❌

❌

✅ (GNU)

bash-argparse

✅

✅

❌ Bash

✅

✅

docopts

✅

✅

❌

✅

✅ (Python)

argbash

✅

✅

❌

✅

✅ (tool)

shflags

✅

✅

❌

✅

✅ (lib)

pass parameters to another script

[!NOTE]

  • objective:

    $ ./b.sh 1 2 3 4 5` -> $ ./a.sh 2 3 4 5
  • b.sh

    #!/bin/bash
    echo """
    b.sh:
      \$1                   : "$1"
      \$#                   : "$#"
      \$@                   : "$@"
      \${@: -1}             : ${@: -1}
      \${@: -2}             : ${@: -2}
      \${@: -3}             : ${@: -2}
      \${@: -\$(( \$#-1 ))} : ${@: -$(( $#-1 ))}
      \$(echo '\${@: -\$(( \$#-1 ))}' | cut -d' ' -f1-) : $(echo "${@: -$(( $#-1 ))}" | cut -d' ' -f1-)
    """
    
    echo -e "\n'~~> ./a.sh \"\${@: -1}\"': ~~~> ./a.sh ${@: -1}:"
    ./a.sh "${@: -1}"
    
    echo -e "\n'~~> ./a.sh \$(echo '\${@: -1}' | cut -d' ' -f1-)': ~~~> ./a.sh $(echo "${@: -1}" | cut -d' ' -f1-):"
    ./a.sh $(echo "${@: -1}" | cut -d' ' -f1-)
    
    echo -e "\n'~~> ./a.sh \"\${@: -4}\"': ~~~> ./a.sh ${@: -4}:"
    ./a.sh "${@: -4}"
    
    echo -e "\n'~~> ./a.sh \$(echo '\${@: -\$(( \$#-1 ))}' | cut -d' ' -f1-)': ~~~> ./a.sh $(echo "${@: -$(( $#-1 ))}" | cut -d' ' -f1-)"
    ./a.sh $(echo "${@: -$(( $#-1 ))}" | cut -d' ' -f1-)
  • a.sh

    echo """
    a.sh:
      \$1: "$1"
      \$#: "$#"
      \$@: "$@"
      \${@: -$(( $#-2 ))}: ${@: -$(( $#-2 ))}
    """
  • result

    $ ./b.sh 1 2 3 4 5
    
    b.sh:
      $1                 : 1
      $#                 : 5
      $@                 : 1 2 3 4 5
      ${@: -1}           : 5
      ${@: -2}           : 4 5
      ${@: -3}           : 4 5
      ${@: -$(( $#-1 ))} : 2 3 4 5
      $(echo '${@: -$(( $#-1 ))}' | cut -d' ' -f1-) : 2 3 4 5
    
    '~~> ./a.sh "${@: -1}"': ~~~> ./a.sh e:
    a.sh:
      $1: 5
      $#: 1
      $@: 5
      ${@: --1}: 5
    
    '~~> ./a.sh $(echo '${@: -1}' | cut -d' ' -f1-)': ~~~> ./a.sh 5:
    a.sh:
      $1: 5
      $#: 1
      $@: 5
      ${@: --1}: 5
    
    '~~> ./a.sh "${@: -4}"': ~~~> ./a.sh 2 3 4 5:
    a.sh:
      $1: b
      $#: 4
      $@: 2 3 4 5
      ${@: -2}: 4 5
    
    '~~> ./a.sh $(echo '${@: -$(( $#-1 ))}' | cut -d' ' -f1-)': ~~~> ./a.sh 2 3 4 5
    a.sh:
      $1: 2
      $#: 4
      $@: 2 3 4 5
      ${@: -2}: 4 5

Manual Case-Loop Parser

[!NOTE]

  • ✅ Pros: Simple, portable

  • ❌ Cons: No built-in validation or help

#!/usr/bin/env bash
# shellcheck disable=SC1079,SC1078

usage="""USAGE
\t$0\t[-h|--help] [-c|--clean] [-t|--tag <tag>] [-i|--image <image>]
\t\t\t[-v|--ver <new-version>] [-n|--name <name>]
\t\t\t[-p|--prop <key=value>]
"""

while test -n "$1"; do
  case "$1" in
    -c | --clean    ) clean=true        ; shift   ;;
    -t | --tag      ) tag=$2            ; shift 2 ;;
    -i | --image    ) image=$2          ; shift 2 ;;
    -v | --ver      ) ver=$2            ; shift 2 ;;
    -n | --name     ) name=$2           ; shift 2 ;;
    -p | --prop     ) prop=$2           ; shift 2 ;;
    -h | --help | * ) echo -e "${usage}"; exit 0  ;;
  esac
done

echo """
  clean : ${clean}
    tag : ${tag}
  image : ${image}
    ver : ${ver}
   name : ${name}
   prop : ${prop}
"""
  • result

    $ ./longopts.sh -h
    USAGE
      ./longopts.sh [-h|--help] [-c|--clean] [-t|--tag <tag>] [-i|--image <image>]
                    [-v|--ver <new-version>] [-n|--name <name>]
                    [-p|--prop <key=value>]
    
    $ ./longopts.sh -c
      clean : true
        tag :
      image :
        ver :
       name :
       prop :
    
    $ ./longopts.sh -c -t 'ttt' -i 'iii' --ver '1.1.1' --name 'name'
      clean : true
        tag : ttt
      image : iii
        ver : 1.1.1
       name : name
       prop :
until [ -z "$1" ]; do # Until all parameters used up
  echo "\$@  : $@ "; shift ;
done

# result
$ ./shift.sh 1 2 3 4 5
$@  : 1 2 3 4 5
$@  : 2 3 4 5
$@  : 3 4 5
$@  : 4 5
$@  : 5

Bash Equals-Separated

for i in "$@"; do
  case $i in
    -e=* | --extension=*  ) EXTENSION="${i#*=}"  ;  shift    ;;
    -s=* | --searchpath=* ) SEARCHPATH="${i#*=}" ;  shift    ;;
    --default             ) DEFAULT=YES          ;  shift    ;;
    -* | --*              ) echo "Unknown option $i"; exit 1 ;;
    *                     )                                  ;;
  esac
done

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)

with one or more values

[!TIP]

  • positional_args+=("$1") to add the arguments to an array one by one

var1=""
flag_verbose=false

# POSIX format using `while [ $# -gt 0 ]`
while [[ $# -gt 0 ]]; do
  case "$1" in
    -v|--verbose ) flag_verbose=true             ;  shift   ;;
    -f|--file    ) var1="$2"                     ;  shift 2 ;;
    --dry-run    ) dryrun=true                   ;  shift   ;;
    -*           ) echo "Unknown option: $1" >&2 ;  exit 1  ;;
    *            ) positional_args+=("$1")       ;  shift   ;;
  esac
done

additional params on --

#!/usr/bin/env bash
# shellcheck disable=SC2051,SC2086

VERBOSE=false
DEBUG=false
MEMORY=
AOPT=
while true; do
  case "$1" in
    -v | --verbose ) VERBOSE=true ; shift   ;;
    -d | --debug   ) DEBUG=true   ; shift   ;;
    -m | --memory  ) MEMORY="$2"  ; shift 2 ;;
    --             ) shift        ; AOPT=$@  ;  break ;;
    *              ) break                  ;;
  esac
done

echo """
  VERBOSE       : ${VERBOSE}
  DEBUG         : ${DEBUG}
  MEMORY        : ${MEMORY}
  AOPT          : ${AOPT}
"""

# example
$ ./param.sh -v -m '256Gi' -- --author 'marslo'
  VERBOSE       : true
  DEBUG         : false
  MEMORY        : 256Gi
  AOPT          : --author marslo

$ ./param.sh -v -- -m '256Gi' --author 'marslo'
  VERBOSE       : true
  DEBUG         : false
  MEMORY        :
  AOPT          : -m 256Gi --author marslo

shift with uncertain params

echo '---------------- before shift -------------------'
echo ".. \$# : $#"
echo ".. \$@ : $@"
echo ".. \$* : $*"

echo '---------------- after shift -------------------'
opt=''

while [[ $# -gt 0 ]]; do
  case "$1" in
    -*) opt+="$1 "; shift;;
     *) break            ;;
  esac
done

echo ".. \$#   : $#"
echo ".. \$@   : $@"
echo ".. \$*   : $*"
echo ".. \$opt : $opt"

if [[ 0 = "$#" ]]; then
  echo -e "\033[0;33mERROR: must provide at least one non-opt param\033[0m"
  exit 2
elif [[ 1 = "$#" ]]; then
  path=''
  params="$1"
else
  path=${*: -1}
  params=${*: 1:$#-1}
fi

echo '---------------- result -------------------'
echo ">> opt    : ${opt}"
echo ">> params : ${params}"
echo ">> path   : ${path}"

POSIX getopts Parser

[!NOTE]

  • ✅ Pros: POSIX, built-in

  • ❌ Cons: No long options, no multi-word values

while getopts "f:vd" opt; do
  case $opt in
    f  ) FILE="$OPTARG" ;;
    v  ) VERBOSE=true   ;;
    d  ) DRYRUN=true    ;;
    \? ) echo "Invalid option: -$OPTARG"; exit 1 ;;
  esac
done
shift $((OPTIND -1))
# Reset in case getopts has been used previously in the shell.
OPTIND=1
output_file=''
verbose=0

while getopts "h?vf:" opt; do
  case "$opt" in
    h|\? ) show_help; exit 0   ;;
    v    ) verbose=1           ;;
    f    ) output_file=$OPTARG ;;
  esac
done

shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift

echo "verbose=$verbose, output_file='$output_file', Leftovers: $@"

GNU getopt Parser

[!NOTE]

  • MacOS: brew install gnu-getopt

  • ✅ Pros: Short + long, nice user UX

  • ❌ Cons: Not portable across BSD/macOS by default (GNU-only)

#!/usr/bin/env bash

ARGS=$(getopt -o f:vd -l file:,verbose,dry-run -- "$@")
eval set -- "$ARGS"

while true; do
  case "$1" in
    -f|--file    ) FILE="$2"    ;  shift 2 ;;
    -v|--verbose ) VERBOSE=true ;  shift   ;;
    --dry-run    ) DRYRUN=true  ;  shift   ;;
    --           ) shift        ;  break   ;;
    *            ) break                   ;;
  esac
done
# option --output/-o requires 1 argument
LONGOPTS=debug,force,output:,verbose
OPTIONS=dfo:v

! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
  # e.g. return value is 1
  #  then getopt has complained about wrong arguments to stdout
  exit 2
fi
# read getopt’s output this way to handle the quoting right:
eval set -- "$PARSED"

d=n f=n v=n outFile=-
# now enjoy the options in order and nicely split until we see --
while true; do
  case "$1" in
    -d|--debug   ) d=y          ;  shift            ;;
    -f|--force   ) f=y          ;  shift            ;;
    -v|--verbose ) v=y          ;  shift            ;;
    -o|--output  ) outFile="$2" ;  shift 2          ;;
    --           ) shift        ;  break            ;;
    *            ) echo "Programming error"; exit 3 ;;
  esac
done

# handle non-option arguments
if [[ $# -ne 1 ]]; then
    echo "$0: A single input file is required."
    exit 4
fi

echo "verbose: $v, force: $f, debug: $d, in: $1, out: $outFile"

bash-argparse Library

[!NOTE]

  • ✅ Pros: Clean, descriptive, built-in help

  • ❌ Cons: Bash-only, external lib needed

# requires sourcing the library
source argparse.sh

argparse "$@" <<EOF
--file -f [arg]    Path to the file
--verbose -v       Enable verbose output
--dry-run          Enable dry-run mode
EOF

docopts

[!NOTE]

  • ✅ Pros: Elegant, self-documenting

  • ❌ Cons: Requires Python + docopts installed

# usage section (docopts parses this!)
read -r -d '' usage <<EOF
Usage:
  script.sh [-v|--verbose] [--dry-run] -f <file>
Options:
  -f --file=<file>     File to process
  -v --verbose         Verbose output
  --dry-run            Simulate actions
EOF

eval "$(docopts -A args -h "$usage" : "$@")"

# access like $args_file, $args_verbose, $args_dry_run

argbash Code Generator

[!NOTE]

  • ✅ Pros: Auto-generates robust scripts

  • ❌ Cons: Requires preprocessing step

# ARG_POSITIONAL_SINGLE([file], [File to process])
# ARG_OPTIONAL_BOOLEAN([verbose], [v], [Enable verbose])
# ARG_OPTIONAL_BOOLEAN([dry-run], [], [Dry run mode])
# ARG_HELP([Script to demonstrate argbash])
# ARGBASH_GO()

# The above is preprocessed by `argbash` into full Bash script

shflags (Google-style shell option lib)

[!NOTE]

  • ✅ Pros: Easy-to-read, Google-style

  • ❌ Cons: Needs external lib and sourcing

. ./shflags

DEFINE_string 'file' '' 'file to use' 'f'
DEFINE_boolean 'verbose' false 'verbose mode' 'v'
DEFINE_boolean 'dry-run' false 'simulate mode' ''

FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"

echo "File: ${FLAGS_file}"

references

|

| |

Anvil/bash-argsparse
docopt/docopt
argbash.dev
matejak/argbash
shflags
lib/shflags/shflags
kward/shflags
如何在 Bash 中解析命令行参数?
* iMarslo: parameter substitution
shell parameter parsers
pass parameters to another script
Manual Case-Loop Parser
Bash Equals-Separated
with one or more values
additional params on --
shift with uncertain params
POSIX getopts Parser
GNU getopt Parser
bash-argparse Library
docopts
argbash Code Generator
shflags (Google-style shell option lib)
references