tags:

views:

61

answers:

3

Hi, 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 etc

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

A: 

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}
Michael Mrozek
+2  A: 

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.

John Kugelman
thanks sir, but your advice are better with quoted or without it?
fixo2020
Can you be more specific about what your program does, what these options are?
John Kugelman
is a client for update any social network, I want make it concurrently, for example, -b update facebook -t update twitter -x update other social network.
fixo2020
OK yeah, definitely require the user to use quotes, then.
John Kugelman
Ok I have resolved this problem, thanks sir.
fixo2020
Sir, I have a last problem, when use this: -a 'string ' string2' why?
fixo2020
Sorry, I'm not sure what you're asking. You can edit your question above and add more to it so you don't have to cram things into these small comment boxes.
John Kugelman
try to execute your first script, and use this: -a 'my string it's here' may be, I have need to slash all quotes into a string?
fixo2020
You can't have a single quote inside single quotes. Use double quotes: `-a "my string it's here"`
John Kugelman
ok thanks much sir...
fixo2020
A: 

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.

Radu C