开发者

bash: store all command-line args after all parameters

how I can create this small script?

For example:

~$ script.sh -b my small string... other things -a other string -c any other string ant e开发者_如何学Pythontc

I want only string, every have a mode.

-b
my small string... other things
-a
other string
-c
any other string ant etc

Anyone know how implements it?

Thanks


Here's a very simple command-line argument loop. The command-line arguments are $1, $2, etc., and the number of command-line arguments is $#. The shift command discards the arguments after we're done with them.

#!/bin/bash

while [[ $# -gt 0 ]]; do
    case "$1" in
        -a) echo "option $1, argument: $2"; shift 2;;
        -b) echo "option $1, argument: $2"; shift 2;;
        -c) echo "option $1, argument: $2"; shift 2;;
        -*) echo "unknown option: $1"; shift;;
        *)  echo "$1"; shift;;
    esac
done

UNIX commands normally expect you to quote multi-word arguments yourself so they show up as single arguments. Usage would look like:

~$ script.sh -b 'my small string... other things' -a 'other string' -c 'any other string ant etc'
option -b, argument: my small string... other things
option -a, argument: other string
option -c, argument: any other string ant etc

Notice how I've quoted the long arguments.

I don't recommend it, but if you really want to pass in multiple words on the command-line but treat them as single arguments, you'll need something a little more complicated:

#!/bin/bash

while [[ $# -gt 0 ]]; do
    case "$1" in
        -a) echo "option: $1"; shift;;
        -b) echo "option: $1"; shift;;
        -c) echo "option: $1"; shift;;

        -*) echo "unknown option: $1"; shift;;

        *)  # Concatenate arguments until we find the next `-x' option.
            OTHER=()

            while [[ $# -gt 0 && ! ( $1 =~ ^- ) ]]; do
                OTHER+=("$1")
                shift
            done

            echo "${OTHER[@]}"
    esac
done

Example usage:

~$ script.sh -b my small string... other things -a other string -c any other string ant etc
option: -b
my small string... other things
option: -a
other string
option: -c
any other string ant etc

Again, though, this usage is not recommended. It goes against UNIX norms and conventions to concatenate arguments like this.


I looked into doing this with getopt, but I don't think it's capable; it's very unusual to treat an unquoted spaced string as one argument. I think you're going to have to do it manually; for example:

long_str=""
for i; do
    if [ ${i:0:1} = '-' ]; then
        [ -z "$long_str" ] || echo ${long_str:1}
        long_str=""
        echo $i
    else
        long_str="$long_str $i"
    fi
done
[ -z "$long_str" ] || echo ${long_str:1}


You should look into quoting the parameters you pass to the script:

For example:

Exhibit A:

script.sh -a one string here -b another string here

Exhibit B:

script.sh -a "one string here" -b "another string here"

and script.sh:

echo "$1:$2:$3:$4"

With exhibit A, the script will display: -a:one:string:here

With exhibit B, the script will display: -a:one string here:-b:another string here

I used the colon to separate things, to make it more obvious.

In Bash, if you quote the parameters you inhibit tokenization of the string, forcing your space separated string to be just one token, instead of many.

As a side note, you should quote each and every variable you use in Bash, just for the case where its value contains token separators (spaces, tabs, etc.), because "$var" and $var are two different things, especially if var="a string with spaces".

Why? Because at one point you'll probably want something like this:

script.sh -a "a string with -b in it" -b "another string, with -a in it"

And if you don't use quoted parameters, but rather attemp heuristics to find where the next parameter is, your code will brake when it hits the fake -a and -b tokens.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜