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.
精彩评论