bash - 関数 - 自作 コマンド 引数




Bashでコマンドライン引数を解析するにはどうすればよいですか? (20)

getopt [s]、POSIX、古いUnixスタイルのない別の解決策

Bruno Bronoskyのソリューションに似ていますが、ここにこれを載せましたgetopt(s)

私のソリューションの主な差別化機能は、オプションtar -xzf foo.tar.gzが同じように連結されていることを可能にすることtar -x -z -f foo.tar.gzです。そして、ちょうど同じようにtarps先頭のハイフンは短いオプションのブロックのためにオプションです(しかし、これは簡単に変更できます)。ロングオプションもサポートされています(ブロックが1で始まる場合、2つのハイフンが必要です)。

サンプルオプション付きのコード

#!/bin/sh

echo
echo "POSIX-compliant getopt(s)-free old-style-supporting option parser from [email protected][se.unix]"
echo

print_usage() {
  echo "Usage:

  $0 {a|b|c} [ARG...]

Options:

  --aaa-0-args
  -a
    Option without arguments.

  --bbb-1-args ARG
  -b ARG
    Option with one argument.

  --ccc-2-args ARG1 ARG2
  -c ARG1 ARG2
    Option with two arguments.

" >&2
}

if [ $# -le 0 ]; then
  print_usage
  exit 1
fi

opt=
while :; do

  if [ $# -le 0 ]; then

    # no parameters remaining -> end option parsing
    break

  elif [ ! "$opt" ]; then

    # we are at the beginning of a fresh block
    # remove optional leading hyphen and strip trailing whitespaces
    opt=$(echo "$1" | sed 's/^-\?\([a-zA-Z0-9\?-]*\)/\1/')

  fi

  # get the first character -> check whether long option
  first_chr=$(echo "$opt" | awk '{print substr($1, 1, 1)}')
  [ "$first_chr" = - ] && long_option=T || long_option=F

  # note to write the options here with a leading hyphen less
  # also do not forget to end short options with a star
  case $opt in

    -)

      # end of options
      shift
      break
      ;;

    a*|-aaa-0-args)

      echo "Option AAA activated!"
      ;;

    b*|-bbb-1-args)

      if [ "$2" ]; then
        echo "Option BBB with argument '$2' activated!"
        shift
      else
        echo "BBB parameters incomplete!" >&2
        print_usage
        exit 1
      fi
      ;;

    c*|-ccc-2-args)

      if [ "$2" ] && [ "$3" ]; then
        echo "Option CCC with arguments '$2' and '$3' activated!"
        shift 2
      else
        echo "CCC parameters incomplete!" >&2
        print_usage
        exit 1
      fi
      ;;

    h*|\?*|-help)

      print_usage
      exit 0
      ;;

    *)

      if [ "$long_option" = T ]; then
        opt=$(echo "$opt" | awk '{print substr($1, 2)}')
      else
        opt=$first_chr
      fi
      printf 'Error: Unknown option: "%s"\n' "$opt" >&2
      print_usage
      exit 1
      ;;

  esac

  if [ "$long_option" = T ]; then

    # if we had a long option then we are going to get a new block next
    shift
    opt=

  else

    # if we had a short option then just move to the next character
    opt=$(echo "$opt" | awk '{print substr($1, 2)}')

    # if block is now empty then shift to the next one
    [ "$opt" ] || shift

  fi

done

echo "Doing something..."

exit 0

使用例については、下記の例を参照してください。

引数付きオプションの位置

その価値があるものについては、引数付きのオプションは最後のオプションではありません(長いオプションだけが必要です)。したがって、ファイル名が続く(動作しますが、そうでない)ためtarfオプションは最後にする必要があります(後の例を参照してください)。tar xzf bar.tar.gztar xfz bar.tar.gz

引数を含む複数のオプション

別のボーナスとして、オプションパラメータは、必要なオプションを持つパラメータによってオプションの順に消費されます。私のスクリプトの出力をコマンドラインabc XYZ(または-abc XYZ)で見てみましょう:

Option AAA activated!
Option BBB with argument 'X' activated!
Option CCC with arguments 'Y' and 'Z' activated!

長いオプションも連結されています

また、ブロック内で最後に発生する場合は、オプションブロックで長いオプションを使用することもできます。したがって、次のコマンドラインはすべて(オプションとその引数が処理される順序を含めて)同等です。

  • -cba ZYX
  • cba ZYX
  • -cb-aaa-0-args ZYX
  • -c-bbb-1-args ZYX -a
  • --ccc-2-args ZY -ba X
  • c ZY b X a
  • -c ZY -b X -a
  • --ccc-2-args ZY --bbb-1-args X --aaa-0-args

これらのすべてが、

Option CCC with arguments 'Z' and 'Y' activated!
Option BBB with argument 'X' activated!
Option AAA activated!
Doing something...

このソリューションにはありません

オプションの引数

オプションの引数を持つオプションは、ハイフンなしのブロックがあるかどうかを調べるなど、少しの作業で可能でなければなりません。ユーザは、任意のパラメータを有するパラメータを有するブロックに続くすべてのブロックの前にハイフンを置く必要がある。たぶん、これはあまりに複雑すぎてユーザーと通信することができないので、この場合は先頭のハイフンを必要とするだけです。

複数の可能なパラメータで状況がさらに複雑になります。私はオプションがオプションであるかどうかを判断することによって、スマートにしようとするオプションを作ることを控えることを勧めます(オプションがオプションの引数として番号を取るなど)。

私は個人的にオプションの引数の代わりに追加のオプションを好みます。

等号で導入されたオプション引数

オプションの引数のように私はこれのファンではない(BTW、異なるパラメータスタイルの長所/短所について議論するためのスレッドがあるのだろうか?)しかし、これを望むなら、おそらくhttp://mywiki.wooledge.org/BashFAQ/035#Manual_loop--long-with-arg=?*case文でhttp://mywiki.wooledge.org/BashFAQ/035#Manual_loophttp://mywiki.wooledge.org/BashFAQ/035#Manual_loopてください(これは、パラメータ結合を行うことはいくつかの努力で可能ですが、読者のための課題として残しています) "私は言葉でそれらを取るようになったが、私は最初から始めた。

その他の注意事項

POSIXに準拠し、私は対処しなければならなかった古くからのBusyboxの設定でも動作します(例えばcut、欠落した場合headなどgetopts)。

さて、私はこの行で呼び出されるスクリプトを持っています:

./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile

またはこの1つ:

./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 

$v$f 、および$dすべてがtrueに設定され、 $outFile/fizz/someOtherFile等しくなるように、これを解析するために受け入れられる方法は何ですか?


より簡潔な方法

script.sh

#!/bin/bash

while [[ "$#" > 0 ]]; do case $1 in
  -d|--deploy) deploy="$2"; shift;;
  -u|--uglify) uglify=1;;
  *) echo "Unknown parameter passed: $1"; exit 1;;
esac; shift; done

echo "Should deploy? $deploy"
echo "Should uglify? $uglify"

使用法:

./script.sh -d dev -u

# OR:

./script.sh --deploy dev --uglify

未処理の引数を保持するソリューション。デモが含まれています。

ここに私の解決策があります。 これは非常に柔軟性があり、他のパッケージとは異なり、外部パッケージを必要とすべきではなく、残りの引数をきれいに処理します。

使用方法は次のとおりです。 ./myscript -flag flagvariable -otherflag flagvar2

validflags行を編集するだけです。ハイフンを先頭に付け、すべての引数を検索します。次に、次の引数をフラグ名として定義します。

./myscript -flag flagvariable -otherflag flagvar2
echo $flag $otherflag
flagvariable flagvar2

メインコード(短いバージョン、詳細な例を下に冗長表示、エラー出力のバージョンも):

#!/usr/bin/env bash
#shebang.io
validflags="rate time number"
count=1
for arg in [email protected]
do
    match=0
    argval=$1
    for flag in $validflags
    do
        sflag="-"$flag
        if [ "$argval" == "$sflag" ]
        then
            declare $flag=$2
            match=1
        fi
    done
        if [ "$match" == "1" ]
    then
        shift 2
    else
        leftovers=$(echo $leftovers $argval)
        shift
    fi
    count=$(($count+1))
done
#Cleanup then restore the leftovers
shift $#
set -- $leftovers

エコーデモが組み込まれた冗長バージョン:

#!/usr/bin/env bash
#shebang.io
rate=30
time=30
number=30
echo "all args
[email protected]"
validflags="rate time number"
count=1
for arg in [email protected]
do
    match=0
    argval=$1
#   argval=$(echo [email protected] | cut -d ' ' -f$count)
    for flag in $validflags
    do
            sflag="-"$flag
        if [ "$argval" == "$sflag" ]
        then
            declare $flag=$2
            match=1
        fi
    done
        if [ "$match" == "1" ]
    then
        shift 2
    else
        leftovers=$(echo $leftovers $argval)
        shift
    fi
    count=$(($count+1))
done

#Cleanup then restore the leftovers
echo "pre final clear args:
[email protected]"
shift $#
echo "post final clear args:
[email protected]"
set -- $leftovers
echo "all post set args:
[email protected]"
echo arg1: $1 arg2: $2

echo leftovers: $leftovers
echo rate $rate time $time number $number

最終的には、無効な引数が渡された場合にこのエラーが出力されます。

#!/usr/bin/env bash
#shebang.io
rate=30
time=30
number=30
validflags="rate time number"
count=1
for arg in [email protected]
do
    argval=$1
    match=0
        if [ "${argval:0:1}" == "-" ]
    then
        for flag in $validflags
        do
                sflag="-"$flag
            if [ "$argval" == "$sflag" ]
            then
                declare $flag=$2
                match=1
            fi
        done
        if [ "$match" == "0" ]
        then
            echo "Bad argument: $argval"
            exit 1
        fi
        shift 2
    else
        leftovers=$(echo $leftovers $argval)
        shift
    fi
    count=$(($count+1))
done
#Cleanup then restore the leftovers
shift $#
set -- $leftovers
echo rate $rate time $time number $number
echo leftovers: $leftovers

長所:それは、それは非常にうまく処理します。これは未使用の引数を保持していますが、他の多くの解決法ではそうしていません。また、スクリプト内で手で定義されていなくても変数を呼び出すことができます。また、対応する引数が与えられていない場合は、変数の事前挿入が可能です。(詳細な例を参照)。

短所:単一の複雑なarg文字列を解析できません。たとえば、-xcvfは単一の引数として処理します。あなたは、この機能を追加する鉱山にいくぶん簡単に追加コードを書くことができます。


位置とフラグベースの引数を混在させる

--param = arg(デリミタ付き)

位置引数の間でフラグを自由に混合する:

./script.sh dumbo 127.0.0.1 --environment=production -q -d
./script.sh dumbo --environment=production 127.0.0.1 --quiet -d

かなり簡潔なアプローチで達成することができます:

# process flags
pointer=1
while [[ $pointer -le $# ]]; do
   param=${!pointer}
   if [[ $param != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
   else
      case $param in
         # paramter-flags with arguments
         -e=*|--environment=*) environment="${param#*=}";;
                  --another=*) another="${param#*=}";;

         # binary flags
         -q|--quiet) quiet=true;;
                 -d) debug=true;;
      esac

      # splice out pointer frame from positional list
      [[ $pointer -gt 1 ]] \
         && set -- ${@:1:((pointer - 1))} ${@:((pointer + 1)):$#} \
         || set -- ${@:((pointer + 1)):$#};
   fi
done

# positional remain
node_name=$1
ip_address=$2

--param arg(スペースで区切られた)

それは、ミックス--flag=value--flag valueスタイルがないのが普通です。

./script.sh dumbo 127.0.0.1 --environment production -q -d

これは少し読みにくいですが、まだ有効です

./script.sh dumbo --environment production 127.0.0.1 --quiet -d

ソース

# process flags
pointer=1
while [[ $pointer -le $# ]]; do
   if [[ ${!pointer} != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
   else
      param=${!pointer}
      ((pointer_plus = pointer + 1))
      slice_len=1

      case $param in
         # paramter-flags with arguments
         -e|--environment) environment=${!pointer_plus}; ((slice_len++));;
                --another) another=${!pointer_plus}; ((slice_len++));;

         # binary flags
         -q|--quiet) quiet=true;;
                 -d) debug=true;;
      esac

      # splice out pointer frame from positional list
      [[ $pointer -gt 1 ]] \
         && set -- ${@:1:((pointer - 1))} ${@:((pointer + $slice_len)):$#} \
         || set -- ${@:((pointer + $slice_len)):$#};
   fi
done

# positional remain
node_name=$1
ip_address=$2

from: digitalpeer.comマイナーな変更

使用法myscript.sh -p=my_prefix -s=dirname -l=libname

#!/bin/bash
for i in "[email protected]"
do
case $i in
    -p=*|--prefix=*)
    PREFIX="${i#*=}"

    ;;
    -s=*|--searchpath=*)
    SEARCHPATH="${i#*=}"
    ;;
    -l=*|--lib=*)
    DIR="${i#*=}"
    ;;
    --default)
    DEFAULT=YES
    ;;
    *)
            # unknown option
    ;;
esac
done
echo PREFIX = ${PREFIX}
echo SEARCH PATH = ${SEARCHPATH}
echo DIRS = ${DIR}
echo DEFAULT = ${DEFAULT}

${i#*=}をよく理解するために、 このガイドの 「部分文字列削除」を検索してください 。 これは機能的に`sed 's/[^=]*=//' <<< "$i"`と呼ばれ、不要なサブプロセスや`echo "$i" | sed 's/[^=]*=//'` `echo "$i" | sed 's/[^=]*=//'`これは2つの不要なサブプロセスを呼び出します。


getoptsは#1をインストールし、#2を同じプラットフォームで実行しようとすると効果的です。 OSXとLinuxは、この点では異なる動作をします。

equals、non-equals、およびbooleanフラグをサポートする(getoptsではない)ソリューションがあります。 たとえば、次のようにスクリプトを実行できます。

./script --arg1=value1 --arg2 value2 --shouldClean

# parse the arguments.
COUNTER=0
ARGS=("[email protected]")
while [ $COUNTER -lt $# ]
do
    arg=${ARGS[$COUNTER]}
    let COUNTER=COUNTER+1
    nextArg=${ARGS[$COUNTER]}

    if [[ $skipNext -eq 1 ]]; then
        echo "Skipping"
        skipNext=0
        continue
    fi

    argKey=""
    argVal=""
    if [[ "$arg" =~ ^\- ]]; then
        # if the format is: -key=value
        if [[ "$arg" =~ \= ]]; then
            argVal=$(echo "$arg" | cut -d'=' -f2)
            argKey=$(echo "$arg" | cut -d'=' -f1)
            skipNext=0

        # if the format is: -key value
        elif [[ ! "$nextArg" =~ ^\- ]]; then
            argKey="$arg"
            argVal="$nextArg"
            skipNext=1

        # if the format is: -key (a boolean flag)
        elif [[ "$nextArg" =~ ^\- ]] || [[ -z "$nextArg" ]]; then
            argKey="$arg"
            argVal=""
            skipNext=0
        fi
    # if the format has not flag, just a value.
    else
        argKey=""
        argVal="$arg"
        skipNext=0
    fi

    case "$argKey" in 
        --source-scmurl)
            SOURCE_URL="$argVal"
        ;;
        --dest-scmurl)
            DEST_URL="$argVal"
        ;;
        --version-num)
            VERSION_NUM="$argVal"
        ;;
        -c|--clean)
            CLEAN_BEFORE_START="1"
        ;;
        -h|--help|-help|--h)
            showUsage
            exit
        ;;
    esac
done

getopt() / getopts()は良いオプションです。 hereから盗んだ:

このミニスクリプトには、「getopt」の簡単な使い方が示されています。

#!/bin/bash
echo "Before getopt"
for i
do
  echo $i
done
args=`getopt abc:d $*`
set -- $args
echo "After getopt"
for i
do
  echo "-->$i"
done

私たちが言ったことは、-a、-b、-c、または-dのいずれかが許可されますが、-cの後には引数が続きます( "c:"はそれを示します)。

これを「g」と呼び、試してみると:

bash-2.05a$ ./g -abc foo
Before getopt
-abc
foo
After getopt
-->-a
-->-b
-->-c
-->foo
-->--

まず2つの引数から始め、 "getopt"はオプションを分割し、それぞれを独自の引数に入れます。 また、 " - "が追加されました。


getopt(1)はAT&Tの短命の間違いでした。

getoptは1984年に作成されましたが、実際には使用できなかったため1986年に既に埋め込まれていました。

getopt(1)マニュアルページには、1986年にBourne Shellに追加された"[email protected]"ではなく"$*"getopts(1)シェルの組み込みとともに追加されています内側にスペースを入れた議論を扱うために。

BTW:シェルスクリプトの長いオプションの解析に興味があるなら、libc(Solaris)とksh93getopt(3)実装の両方が、ロングオプションをshortのエイリアスとしてサポートする均一なロングオプションの実装を追加したオプション。 これにより、 ksh93Bourne Shellgetoptsを介してロングオプション用の統一インタフェースを実装します。

Bourne Shellのmanページから得られる長いオプションの例:

getopts "f:(file)(input-file)o:(output-file)" OPTX "[email protected]"

Bourne Shellとksh93の両方でオプションエイリアスを使用できる時間を示します。

最近のBourne Shellのmanページを参照してください:

http://schillix.sourceforge.net/man/man1/bosh.1.html

OpenSolarisからのgetopt(3)のマニュアルページ:

http://schillix.sourceforge.net/man/man3c/getopt.3c.html

最後に、getopt(1)のマニュアルページで古い$ *を確認します:

http://schillix.sourceforge.net/man/man1/getopt.1.html


ここでは可変配列を使ったBruno Bronoskyの答えの改善された解決法があります。

パラメータの位置を混在させ、オプションなしで順序を保持するパラメータ配列を与えることができます

#!/bin/bash

echo [email protected]

PARAMS=()
SOFT=0
SKIP=()
for i in "[email protected]"
do
case $i in
    -n=*|--skip=*)
    SKIP+=("${i#*=}")
    ;;
    -s|--soft)
    SOFT=1
    ;;
    *)
        # unknown option
        PARAMS+=("$i")
    ;;
esac
done
echo "SKIP            = ${SKIP[@]}"
echo "SOFT            = $SOFT"
    echo "Parameters:"
    echo ${PARAMS[@]}

例:

$ ./test.sh parameter -s somefile --skip=.c --skip=.obj
parameter -s somefile --skip=.c --skip=.obj
SKIP            = .c .obj
SOFT            = 1
Parameters:
parameter somefile

ここで私のアプローチは - regexpを使用しています。

  • getoptsはありません
  • 短いパラメータのブロックを処理する -qwerty
  • 短いパラメータを処理する -q -w -e
  • 長いオプションを処理する --qwerty
  • shortまたはlongオプションに属性を渡すことができます(短いオプションのブロックを使用している場合は、最後のオプションに属性が付加されます)
  • スペースを使用したり=属性を提供したりすることはできますが、ハイフン+スペースの「区切り文字」が見つかるまで属性が一致するため、--q=qwe ty qwe ty1つの属性
  • 上記のすべての組み合わせを処理するので-oa -op attr ibute --option=att ribu te --op-tion attribute --option att-ribute有効です

スクリプト:

#!/usr/bin/env sh

help_menu() {
  echo "Usage:

  ${0##*/} [-h][-l FILENAME][-d]

Options:

  -h, --help
    display this help and exit

  -l, --logfile=FILENAME
    filename

  -d, --debug
    enable debug
  "
}

parse_options() {
  case $opt in
    h|help)
      help_menu
      exit
     ;;
    l|logfile)
      logfile=${attr}
      ;;
    d|debug)
      debug=true
      ;;
    *)
      echo "Unknown option: ${opt}\nRun ${0##*/} -h for help.">&2
      exit 1
  esac
}
[email protected]

until [ "$options" = "" ]; do
  if [[ $options =~ (^ *(--([a-zA-Z0-9-]+)|-([a-zA-Z0-9-]+))(( |=)(([\_\.\?\/\\a-zA-Z0-9]?[ -]?[\_\.\?a-zA-Z0-9]+)+))?(.*)|(.+)) ]]; then
    if [[ ${BASH_REMATCH[3]} ]]; then # for --option[=][attribute] or --option[=][attribute]
      opt=${BASH_REMATCH[3]}
      attr=${BASH_REMATCH[7]}
      options=${BASH_REMATCH[9]}
    elif [[ ${BASH_REMATCH[4]} ]]; then # for block options -qwert[=][attribute] or single short option -a[=][attribute]
      pile=${BASH_REMATCH[4]}
      while (( ${#pile} > 1 )); do
        opt=${pile:0:1}
        attr=""
        pile=${pile/${pile:0:1}/}
        parse_options
      done
      opt=$pile
      attr=${BASH_REMATCH[7]}
      options=${BASH_REMATCH[9]}
    else # leftovers that don't match
      opt=${BASH_REMATCH[10]}
      options=""
    fi
    parse_options
  fi
done

これは、スタック内のどこかで同時にgetoptsを実行しないようにするための関数です。

function waitForWeb () {
   local OPTIND=1 OPTARG OPTION
   local host=localhost port=8080 proto=http
   while getopts "h:p:r:" OPTION; do
      case "$OPTION" in
      h)
         host="$OPTARG"
         ;;
      p)
         port="$OPTARG"
         ;;
      r)
         proto="$OPTARG"
         ;;
      esac
   done
...
}

これはまた、値を設定することができ、誰かが入力を提供している場合は、デフォルト値をその値で上書きすることができます。

myscript.sh -f ./serverlist.txtまたはちょうど./myscript.sh(それはデフォルトを取ります)

    #!/bin/bash
    # --- set the value, if there is inputs, override the defaults.

    HOME_FOLDER="${HOME}/owned_id_checker"
    SERVER_FILE_LIST="${HOME_FOLDER}/server_list.txt"

    while [[ $# > 1 ]]
    do
    key="$1"
    shift

    case $key in
        -i|--inputlist)
        SERVER_FILE_LIST="$1"
        shift
        ;;
    esac
    done


    echo "SERVER LIST   = ${SERVER_FILE_LIST}"

無視する別の例を追加する危険性があるので、ここに私の計画があります。

  • ハンドル-n arg--name=arg
  • 最後に引数を与える
  • スペルが間違っていると正常なエラーが表示されます
  • 互換性があり、bashismsを使用しない
  • 読み取り可能で、ループ内で状態を維持する必要はありません

それが誰かにとって有益だと思っています。

while [ "$#" -gt 0 ]; do
  case "$1" in
    -n) name="$2"; shift 2;;
    -p) pidfile="$2"; shift 2;;
    -l) logfile="$2"; shift 2;;

    --name=*) name="${1#*=}"; shift 1;;
    --pidfile=*) pidfile="${1#*=}"; shift 1;;
    --logfile=*) logfile="${1#*=}"; shift 1;;
    --name|--pidfile|--logfile) echo "$1 requires an argument" >&2; exit 1;;

    -*) echo "unknown option: $1" >&2; exit 1;;
    *) handle_argument "$1"; shift 1;;
  esac
done

私の答えは主にBruno Bronoskyの答えに基づいていますが、私はかなり純粋に2つの純粋なbash実装を1つにまとめました。

# As long as there is at least one more argument, keep looping
while [[ $# -gt 0 ]]; do
    key="$1"
    case "$key" in
        # This is a flag type option. Will catch either -f or --foo
        -f|--foo)
        FOO=1
        ;;
        # Also a flag type option. Will catch either -b or --bar
        -b|--bar)
        BAR=1
        ;;
        # This is an arg value type option. Will catch -o value or --output-file value
        -o|--output-file)
        shift # past the key and to the value
        OUTPUTFILE="$1"
        ;;
        # This is an arg=value type option. Will catch -o=value or --output-file=value
        -o=*|--output-file=*)
        # No need to shift here since the value is part of the same string
        OUTPUTFILE="${key#*=}"
        ;;
        *)
        # Do whatever you want with extra options
        echo "Unknown option '$key'"
        ;;
    esac
    # Shift after checking all the cases to get the next option
    shift
done

これにより、スペースで区切られたオプション/値と同じ定義値の両方を持つことができます。

スクリプトを実行するには、次のようにします。

./myscript --foo -b -o /fizz/file.txt

と同様:

./myscript -f --bar -o=/fizz/file.txt

両方とも同じ最終結果を持つ必要があります。

PROS:

  • -arg =値と-arg値の両方を許容

  • bashで使用できる任意の引数名で動作します。

    • 意味-aまたは-argまたは-argまたは-argまたは何でも
  • 純粋なバッシュ。 getoptやgetoptsを学ぶ/使用する必要はありません

短所:

  • argsを組み合わせることはできません

    • 意味はない-abc。 -a -b -cを実行する必要があります。

これらは私の頭の上から考えられる唯一の賛否両論です


私はこれが使用するのに十分シンプルだと思います:

#!/bin/bash
#

readopt='getopts $opts opt;rc=$?;[ $rc$opt == 0? ]&&exit 1;[ $rc == 0 ]||{ shift $[OPTIND-1];false; }'

opts=vfdo:

# Enumerating options
while eval $readopt
do
    echo OPT:$opt ${OPTARG+OPTARG:$OPTARG}
done

# Enumerating arguments
for arg
do
    echo ARG:$arg
done

呼び出しの例:

./myscript -v -do /fizz/someOtherFile -f ./foo/bar/someFile
OPT:v 
OPT:d 
OPT:o OPTARG:/fizz/someOtherFile
OPT:f 
ARG:./foo/bar/someFile

私はスクリプトで移植性のある解析を書いて問題を見つけましたので、スクリプトの引数解析コードを生成できるFOSSコードジェネレータであるArgbashを書いています。

https://argbash.io


私は素晴らしいbashツールを書くbashヘルパーを書いています

プロジェクトホーム:https://gitlab.mbedsys.org/mbedsys/bashopts : https://gitlab.mbedsys.org/mbedsys/bashopts

例:

#!/bin/bash -ei

# load the library
. bashopts.sh

# Enable backtrace dusplay on error
trap 'bashopts_exit_handle' ERR

# Initialize the library
bashopts_setup -n "$0" -d "This is myapp tool description displayed on help message" -s "$HOME/.config/myapprc"

# Declare the options
bashopts_declare -n first_name -l first -o f -d "First name" -t string -i -s -r
bashopts_declare -n last_name -l last -o l -d "Last name" -t string -i -s -r
bashopts_declare -n display_name -l display-name -t string -d "Display name" -e "\$first_name \$last_name"
bashopts_declare -n age -l number -d "Age" -t number
bashopts_declare -n email_list -t string -m add -l email -d "Email adress"

# Parse arguments
bashopts_parse_args "[email protected]"

# Process argument
bashopts_process_args

助けを与えるだろう:

NAME:
    ./example.sh - This is myapp tool description displayed on help message

USAGE:
    [options and commands] [-- [extra args]]

OPTIONS:
    -h,--help                          Display this help
    -n,--non-interactive true          Non interactive mode - [$bashopts_non_interactive] (type:boolean, default:false)
    -f,--first "John"                  First name - [$first_name] (type:string, default:"")
    -l,--last "Smith"                  Last name - [$last_name] (type:string, default:"")
    --display-name "John Smith"        Display name - [$display_name] (type:string, default:"$first_name $last_name")
    --number 0                         Age - [$age] (type:number, default:0)
    --email                            Email adress - [$email_list] (type:string, default:"")

楽しい :)


bash-modules "arguments"モジュールを使用するbash-modules

例:

#!/bin/bash
. import.sh log arguments

NAME="world"

parse_arguments "-n|--name)NAME;S" -- "[email protected]" || {
  error "Cannot parse command line."
  exit 1
}

info "Hello, $NAME!"

次の例ではgetopt、and evalHEREDOCand を使用して、shift短いパラメータと長いパラメータを処理する方法を示します。また、switch / caseステートメントは簡潔で簡単に実行できます。

#!/usr/bin/env bash

# usage function
function usage()
{
   cat << HEREDOC

   Usage: $progname [--num NUM] [--time TIME_STR] [--verbose] [--dry-run]

   optional arguments:
     -h, --help           show this help message and exit
     -n, --num NUM        pass in a number
     -t, --time TIME_STR  pass in a time string
     -v, --verbose        increase the verbosity of the bash script
     --dry-run            do a dry run, don't change any files

HEREDOC
}  

# initialize variables
progname=$(basename $0)
verbose=0
dryrun=0
num_str=
time_str=

# use getopt and store the output into $OPTS
# note the use of -o for the short options, --long for the long name options
# and a : for any option that takes a parameter
OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "[email protected]")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; usage; exit 1 ; fi
eval set -- "$OPTS"

while true; do
  # uncomment the next line to see how shift is working
  # echo "\$1:\"$1\" \$2:\"$2\""
  case "$1" in
    -h | --help ) usage; exit; ;;
    -n | --num ) num_str="$2"; shift 2 ;;
    -t | --time ) time_str="$2"; shift 2 ;;
    --dry-run ) dryrun=1; shift ;;
    -v | --verbose ) verbose=$((verbose + 1)); shift ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

if (( $verbose > 0 )); then

   # print out all the parameters we read in
   cat <<-EOM
   num=$num_str
   time=$time_str
   verbose=$verbose
   dryrun=$dryrun
EOM
fi

# The rest of your script below

上記のスクリプトの最も重要な行は次のとおりです。

OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "[email protected]")
if [ $? != 0 ] ; then echo "Error in command line arguments." >&2 ; exit 1 ; fi
eval set -- "$OPTS"

while true; do
  case "$1" in
    -h | --help ) usage; exit; ;;
    -n | --num ) num_str="$2"; shift 2 ;;
    -t | --time ) time_str="$2"; shift 2 ;;
    --dry-run ) dryrun=1; shift ;;
    -v | --verbose ) verbose=$((verbose + 1)); shift ;;
    -- ) shift; break ;;
    * ) break ;;
  esac
done

短く、ポイントまで、読みやすく、すべてのことを処理します(IMHO)。

誰かを助けることを願っています。






arguments