Specify command line arguments like name=value pairs for shell script

前端 未结 5 1144
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-10 07:38

Is it possible to pass command line arguments to shell script as name value pairs, something like

myscript action=build module=core

and th

相关标签:
5条回答
  • 2020-12-10 08:16

    In the Bourne shell, there is a seldom-used option '-k' which automatically places any values specified as name=value on the command line into the environment. Of course, the Bourne/Korn/POSIX shell family (including bash) also do that for name=value items before the command name:

    name1=value1 name2=value2 command name3=value3 -x name4=value4 abc
    

    Under normal POSIX-shell behaviour, the command is invoked with name1 and name2 in the environment, and with four arguments. Under the Bourne (and Korn and bash, but not POSIX) shell -k option, it is invoked with name1, name2, name3, and name4 in the environment and just two arguments. The bash manual page (as in man bash) doesn't mention the equivalent of -k but it works like the Bourne and Korn shells do. I don't think I've ever used it (the -k option) seriously.

    There is no way to tell from within the script (command) that the environment variables were specified solely for this command; they are simply environment variables in the environment of that script.

    This is the closest approach I know of to what you are asking for. I do not think anything equivalent exists for the C shell family. I don't know of any other argument parser that sets variables from name=value pairs on the command line.


    With some fairly major caveats (it is relatively easy to do for simple values, but hard to deal with values containing shell meta-characters), you can do:

    case $1 in
    (*=*) eval $1;;
    esac
    

    This is not the C shell family. The eval effectively does the shell assignment.

    arg=name1=value1
    echo $name1
    eval $arg
    echo $name1
    
    0 讨论(0)
  • 2020-12-10 08:17

    This worked for me:

    for ARGUMENT in "$@"
    do
    
        KEY=$(echo $ARGUMENT | cut -f1 -d=)
        VALUE=$(echo $ARGUMENT | cut -f2 -d=)   
    
        case "$KEY" in
                STEPS)              STEPS=${VALUE} ;;
                REPOSITORY_NAME)    REPOSITORY_NAME=${VALUE} ;;     
                *)   
        esac    
    
    
    done
    
    echo "STEPS = $STEPS"
    echo "REPOSITORY_NAME = $REPOSITORY_NAME"
    

    Usage

    bash my_scripts.sh  STEPS="ABC" REPOSITORY_NAME="stackexchange"
    

    Console result :

    STEPS = ABC
    REPOSITORY_NAME = stackexchange
    

    STEPS and REPOSITORY_NAME are ready to use in the script.

    It does not matter what order the arguments are in.

    HTH

    0 讨论(0)
  • 2020-12-10 08:17

    Extending on Jonathan's answer, this worked nicely for me:

    #!/bin/bash
    if [ "$#" -eq "0" ]; then
      echo "Error! Usage: Remind me how this works again ..."
      exit 1
    fi
    
    while [[ "$#" > "0" ]]
    do
      case $1 in
        (*=*) eval $1;;
      esac
    shift
    done
    
    0 讨论(0)
  • 2020-12-10 08:28

    It's quite an old question, but still valid I have not found the cookie cut solution. I combined the above answers. For my needs I created this solution; this works even with white space in the argument's value.

    Save this as argparse.sh

    #!/bin/bash
    
    : ${1?
      'Usage:
      $0 --<key1>="<val1a> <val1b>" [ --<key2>="<val2a> <val2b>" | --<key3>="<val3>" ]'
    }
    
    declare -A args
    while [[ "$#" > "0" ]]; do
      case "$1" in 
        (*=*)
            _key="${1%%=*}" &&  _key="${_key/--/}" && _val="${1#*=}"
            args[${_key}]="${_val}"
            (>&2 echo -e "key:val => ${_key}:${_val}")
            ;;
      esac
      shift
    done
    (>&2 echo -e "Total args: ${#args[@]}; Options: ${args[@]}")
    
    ## This additional can check for specific key
    [[ -n "${args['path']+1}" ]] && (>&2 echo -e "key: 'path' exists") || (>&2 echo -e "key: 'path' does NOT exists");
    

    @Example: Note, arguments to the script can have optional prefix --

    ./argparse.sh --x="blah"
    ./argparse.sh --x="blah" --yy="qwert bye"
    ./argparse.sh x="blah" yy="qwert bye"
    

    Some interesting use cases for this script:

    ./argparse.sh --path="$(ls -1)"
    ./argparse.sh --path="$(ls -d -1 "$PWD"/**)"
    

    Above script created as gist, Refer: argparse.sh

    0 讨论(0)
  • 2020-12-10 08:37
    env action=build module=core myscript
    

    You said you're using tcsh. For Bourne-based shells, you can drop the "env", though it's harmless to leave it there. Note that this applies to the shell from which you run the command, not to the shell used to implement myscript.

    If you specifically want the name=value pairs to follow the command name, you'll need to do some work inside myscript.

    0 讨论(0)
提交回复
热议问题