bash argument case for args in $@

2020-05-23 02:44发布

I have a script with a long list of OPTIONAL arguments. some have associated values.

Such as:

.script --first 2012-12-25 --last 2012-12-26 --copy --remove
.script --first 2012-12-25 

Thus the following case statement:

for arg in "$@"
do
    case $arg in
        "--first" )
           START_DATE=$arg;;
        "--last" )
           END_DATE=$arg;;
        "--copy" )
           COPY=true;;
        "--remove" )
           REMOVE=true;;

# ... and so on
   esac
done

My problem:

that needs a increment $arg+1 type statement to get the following arg (in some cases).

How is that possible?

I'm also happy to do a substring such .script --first2012-12-25 --last2012-12-26

and not sure how to proceed there.

标签: bash shell
5条回答
smile是对你的礼貌
2楼-- · 2020-05-23 02:59

If you have more than one option, and especially options with values mixed with options without values, let getopts do the work for you.

查看更多
Evening l夕情丶
3楼-- · 2020-05-23 03:10

getopts cannot have optional arguments it seems. otherwise great.

my solution

loop the $@ and setting a variable equal to x=$arg do the case switch on that variable (rather than arg)

that worked fine for arguments of the type --startdate 2012-12-25 --enddate 2012-12-29

but did not work for --remove that has no following argument.

therefore tack on stuff (unlikely argument) onto the arg string.

leaving the following

argc="$@ jabberwhocky" 
echo $argc
x=0
# x=0 for unset variable
for arg in $argc
do
   case $x in
        "--start" )
          STARTDATE=$arg ;;
        "--end" )
          ENDDATE=$arg ;;
        "--copy" )
          COPY=true;;
        "--remove" )
          REMOVE=true;;

... and so on....

    esac
    x=$arg
done
查看更多
三岁会撩人
4楼-- · 2020-05-23 03:13

You can allow both --a=arg or -a arg options with a little more work:

START_DATE="$(date '+%Y-%m-%d')";
LAST_DATE="$(date '+%Y-%m-%d')";
while [[ $# -gt 0 ]] && [[ "$1" == "--"* ]] ;
do
    opt="$1";
    shift;              #expose next argument
    case "$opt" in
        "--" ) break 2;;
        "--first" )
           START_DATE="$1"; shift;;
        "--first="* )     # alternate format: --first=date
           START_DATE="${opt#*=}";;
        "--last" )
           LAST_DATE="$1"; shift;;
        "--last="* )
           LAST_DATE="${opt#*=}";;
        "--copy" )
           COPY=true;;
        "--remove" )
           REMOVE=true;;
        "--optional" )
           OPTIONAL="$optional_default";;     #set to some default value
        "--optional=*" )
           OPTIONAL="${opt#*=}";;             #take argument
        *) echo >&2 "Invalid option: $@"; exit 1;;
   esac
done

Note the --optional argument uses a default value if "=" is not used, else it sets the value in the normal way.

查看更多
地球回转人心会变
5楼-- · 2020-05-23 03:14

$@ is an array, & not a simple variable.

You can capture it to a local variable as x=("$@") & then use array x with indices as 0 to ($# - 1).

To access individual elements, use ${x[$i]}. You can NOT directly use ${@[$i]}, however.

So instead of for arg in "$@" loop, you will have i=0; while [ $i -lt $# ]; do loop.

查看更多
再贱就再见
6楼-- · 2020-05-23 03:17

Use shift in the end of each case statement.

Quote from a bash manual:

shift [n]

The positional parameters from n+1 ... are renamed to $1 .... Parameters represented by the numbers $# down to $#-n+1 are unset. n must be a non-negative number less than or equal to $#. If n is 0, no parameters are changed. If n is not given, it is assumed to be 1. If n is greater than $#, the positional parameters are not changed. The return status is greater than zero if n is greater than $# or less than zero; otherwise 0.

查看更多
登录 后发表回答