it-swarm.com.de

Wie man Argumente mit Flags in Bash bekommt

Ich weiß, dass ich in bash leicht so positionierte Parameter erhalten kann:

$0 oder $1

Ich möchte in der Lage sein, Flag-Optionen wie diese zu verwenden, um anzugeben, für was jeder Parameter verwendet wird:

mysql -u user -h Host

Was ist der beste Weg, um -u param Wert und -h param Wert nach Flag statt nach Position?

247
Stann

Dies ist die Redewendung, die ich normalerweise benutze:

while test $# -gt 0; do
  case "$1" in
    -h|--help)
      echo "$package - attempt to capture frames"
      echo " "
      echo "$package [options] application [arguments]"
      echo " "
      echo "options:"
      echo "-h, --help                show brief help"
      echo "-a, --action=ACTION       specify an action to use"
      echo "-o, --output-dir=DIR      specify a directory to store output in"
      exit 0
      ;;
    -a)
      shift
      if test $# -gt 0; then
        export PROCESS=$1
      else
        echo "no process specified"
        exit 1
      fi
      shift
      ;;
    --action*)
      export PROCESS=`echo $1 | sed -e 's/^[^=]*=//g'`
      shift
      ;;
    -o)
      shift
      if test $# -gt 0; then
        export OUTPUT=$1
      else
        echo "no output dir specified"
        exit 1
      fi
      shift
      ;;
    --output-dir*)
      export OUTPUT=`echo $1 | sed -e 's/^[^=]*=//g'`
      shift
      ;;
    *)
      break
      ;;
  esac
done

Schwerpunkte sind:

  • $# ist die Anzahl der Argumente
  • while-Schleife betrachtet alle angegebenen Argumente und gleicht deren Werte in einer case-Anweisung ab
  • schicht nimmt den ersten weg. Sie können innerhalb einer case-Anweisung mehrere Male verschieben, um mehrere Werte zu übernehmen.
254
Flexo

In diesem Beispiel wird der in Bash integrierte Befehl getopts verwendet. Er stammt aus dem Google Shell Style Guide :

a_flag=''
b_flag=''
files=''
verbose='false'

print_usage() {
  printf "Usage: ..."
}

while getopts 'abf:v' flag; do
  case "${flag}" in
    a) a_flag='true' ;;
    b) b_flag='true' ;;
    f) files="${OPTARG}" ;;
    v) verbose='true' ;;
    *) print_usage
       exit 1 ;;
  esac
done

Hinweis: Wenn auf ein Zeichen ein Doppelpunkt folgt (z. B. f:), für diese Option wird ein Argument erwartet.

Anwendungsbeispiel: ./script -v -a -b -f filename

Die Verwendung von getopts hat gegenüber der akzeptierten Antwort mehrere Vorteile:

  • die while-Bedingung ist viel besser lesbar und zeigt, welche Optionen akzeptiert werden
  • sauberer Code; kein zählen der anzahl der parameter und verschieben
  • sie können an Optionen teilnehmen (z. B. -a -b -c-abc)

Ein großer Nachteil ist jedoch, dass keine langen Optionen, sondern nur Optionen mit einem Zeichen unterstützt werden.

362
Dennis

getopt ist dein Freund .. ein einfaches Beispiel:

function f () {
TEMP=`getopt --long -o "u:h:" "[email protected]"`
eval set -- "$TEMP"
while true ; do
    case "$1" in
        -u )
            user=$2
            shift 2
        ;;
        -h )
            Host=$2
            shift 2
        ;;
        *)
            break
        ;;
    esac 
done;

echo "user = $user, Host = $Host"
}

f -u myself -h some_Host

In Ihrem Verzeichnis/usr/bin sollten sich verschiedene Beispiele befinden.

44
Shizzmo

Ich denke, dies wäre ein einfacheres Beispiel dafür, was Sie erreichen wollen. Externe Tools sind nicht erforderlich. Mit den in Bash integrierten Tools können Sie die Arbeit erledigen.

function DOSOMETHING {

   while test $# -gt 0; do
           case "$1" in
                -first)
                    shift
                    first_argument=$1
                    shift
                    ;;
                -last)
                    shift
                    last_argument=$1
                    shift
                    ;;
                *)
                   echo "$1 is not a recognized flag!"
                   return 1;
                   ;;
          esac
  done  

  echo "First argument : $first_argument";
  echo "Last argument : $last_argument";
 }

Auf diese Weise können Sie Flags verwenden, damit Sie unabhängig von der Reihenfolge, in der Sie die Parameter übergeben, das richtige Verhalten erhalten.

Beispiel

 DOSOMETHING -last "Adios" -first "Hola"

Ausgabe :

 First argument : Hola
 Last argument : Adios

Sie können diese Funktion Ihrem Profil hinzufügen oder in ein Skript einfügen.

Vielen Dank!

Bearbeiten: Speichern Sie diese als Datei und führen Sie sie dann als yourfile.sh -last "Adios" -first "Hola"

#!/bin/bash
while test $# -gt 0; do
           case "$1" in
                -first)
                    shift
                    first_argument=$1
                    shift
                    ;;
                -last)
                    shift
                    last_argument=$1
                    shift
                    ;;
                *)
                   echo "$1 is not a recognized flag!"
                   return 1;
                   ;;
          esac
  done  

  echo "First argument : $first_argument";
  echo "Last argument : $last_argument";
8
Matias Barrios

Eine andere Alternative wäre die Verwendung des folgenden Beispiels, mit dem Sie lange - image oder kurze - i Tags verwenden und auch kompilierte - i = "example.jpg" oder separate - i example.jpg Methoden zur Übergabe von Argumenten.

# declaring a couple of associative arrays
declare -A arguments=();  
declare -A variables=();

# declaring an index integer
declare -i index=1;

# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";  
variables["--git-user"]="git_user";  
variables["-gb"]="git_branch";  
variables["--git-branch"]="git_branch";  
variables["-dbr"]="db_fqdn";  
variables["--db-redirect"]="db_fqdn";  
variables["-e"]="environment";  
variables["--environment"]="environment";

# [email protected] here represents all arguments passed in
for i in "[email protected]"  
do  
  arguments[$index]=$i;
  prev_index="$(expr $index - 1)";

  # this if block does something akin to "where $i contains ="
  # "%=*" here strips out everything from the = to the end of the argument leaving only the label
  if [[ $i == *"="* ]]
    then argument_label=${i%=*} 
    else argument_label=${arguments[$prev_index]}
  fi

  # this if block only evaluates to true if the argument label exists in the variables array
  if [[ -n ${variables[$argument_label]} ]]
    then
        # dynamically creating variables names using declare
        # "#$argument_label=" here strips out the label leaving only the value
        if [[ $i == *"="* ]]
            then declare ${variables[$argument_label]}=${i#$argument_label=} 
            else declare ${variables[$argument_label]}=${arguments[$index]}
        fi
  fi

  index=index+1;
done;

# then you could simply use the variables like so:
echo "$git_user";
5
Robert McMahan

Ich mag die Antwort von Robert McMahan am besten, da es am einfachsten erscheint, gemeinsam nutzbare Include-Dateien für Ihre Skripte zu erstellen. Aber es scheint einen Fehler in der Zeile zu haben if [[ -n ${variables[$argument_label]} ]] wirft die Nachricht "variables: bad array subscript" aus. Ich kann keinen Kommentar abgeben, und ich bezweifle, dass dies die richtige "Lösung" ist, sondern dass if in if [[ -n $argument_label ]] ; then räumt auf.

Hier ist der Code, mit dem ich gelandet bin. Wenn Sie einen besseren Weg kennen, fügen Sie bitte einen Kommentar zu Roberts Antwort hinzu.

Include-Datei "flags-declares.sh"

# declaring a couple of associative arrays
declare -A arguments=();
declare -A variables=();

# declaring an index integer
declare -i index=1;

Include-Datei "flags-arguments.sh"

# [email protected] here represents all arguments passed in
for i in "[email protected]"
do
  arguments[$index]=$i;
  prev_index="$(expr $index - 1)";

  # this if block does something akin to "where $i contains ="
  # "%=*" here strips out everything from the = to the end of the argument leaving only the label
  if [[ $i == *"="* ]]
    then argument_label=${i%=*}
    else argument_label=${arguments[$prev_index]}
  fi

  if [[ -n $argument_label ]] ; then
    # this if block only evaluates to true if the argument label exists in the variables array
    if [[ -n ${variables[$argument_label]} ]] ; then
      # dynamically creating variables names using declare
      # "#$argument_label=" here strips out the label leaving only the value
      if [[ $i == *"="* ]]
        then declare ${variables[$argument_label]}=${i#$argument_label=} 
        else declare ${variables[$argument_label]}=${arguments[$index]}
      fi
    fi
  fi

  index=index+1;
done;

Deine "script.sh"

. bin/includes/flags-declares.sh

# any variables you want to use here
# on the left left side is argument label or key (entered at the command line along with it's value) 
# on the right side is the variable name the value of these arguments should be mapped to.
# (the examples above show how these are being passed into this script)
variables["-gu"]="git_user";
variables["--git-user"]="git_user";
variables["-gb"]="git_branch";
variables["--git-branch"]="git_branch";
variables["-dbr"]="db_fqdn";
variables["--db-redirect"]="db_fqdn";
variables["-e"]="environment";
variables["--environment"]="environment";

. bin/includes/flags-arguments.sh

# then you could simply use the variables like so:
echo "$git_user";
echo "$git_branch";
echo "$db_fqdn";
echo "$environment";
3
Michael

Wenn Sie mit Python argparse vertraut sind und nichts dagegen haben, python zum Parsen von bash-Argumenten aufzurufen, gibt es einen Teil des Codes, den ich sehr hilfreich und hilfreich fand Super einfach zu bedienen namens argparse-bash https://github.com/nhoffman/argparse-bash

Beispielentnahme aus ihrem Skript example.sh:

#!/bin/bash

source $(dirname $0)/argparse.bash || exit 1
argparse "[email protected]" <<EOF || exit 1
parser.add_argument('infile')
parser.add_argument('outfile')
parser.add_argument('-a', '--the-answer', default=42, type=int,
                    help='Pick a number [default %(default)s]')
parser.add_argument('-d', '--do-the-thing', action='store_true',
                    default=False, help='store a boolean [default %(default)s]')
parser.add_argument('-m', '--multiple', nargs='+',
                    help='multiple values allowed')
EOF

echo required infile: "$INFILE"
echo required outfile: "$OUTFILE"
echo the answer: "$THE_ANSWER"
echo -n do the thing?
if [[ $DO_THE_THING ]]; then
    echo " yes, do it"
else
    echo " no, do not do it"
fi
echo -n "arg with multiple values: "
for a in "${MULTIPLE[@]}"; do
    echo -n "[$a] "
done
echo
1
Linh

Ich schlage ein einfaches TLDR vor :; Beispiel für den Uneingeweihten.

Erstellen Sie ein Bash-Skript mit dem Namen helloworld.sh

#!/bin/bash

while getopts "n:" arg; do
  case $arg in
    n) Name=$OPTARG;;
  esac
done

echo "Hello $Name!"

Sie können dann beim Ausführen des Skripts einen optionalen Parameter -n Übergeben.

Führen Sie das Skript als solches aus:

$ bash helloworld.sh -n 'World'

Ausgabe

$ Hello World!

Notizen

Wenn Sie mehrere Parameter verwenden möchten:

  1. erweitern Sie while getops "n:" arg: do um weitere Parameter wie while getops "n:o:p:" arg: do
  2. erweitern Sie den Fallschalter mit zusätzlichen variablen Zuweisungen. Wie o) Option=$OPTARG Und p) Parameter=$OPTARG
0
pijemcolu