Wie schreibe ich ein Bash-Skript, das optionale Eingabeargumente verwendet?

471

Ich möchte, dass mein Skript eine optionale Eingabe annehmen kann.

zB derzeit ist mein Skript

#!/bin/bash
somecommand foo

aber ich möchte es sagen:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
Abe
quelle
3
Bash oder POSIX? Mit Bash gibt es mehr Möglichkeiten
user123444555621
@ Pumbaa80 bash - Ich habe die Tags aktualisiert.
Abe

Antworten:

706

Sie können die Standardwertsyntax verwenden:

somecommand ${1:-foo}

Das Obige wird, wie im Bash-Referenzhandbuch - 3.5.3 Erweiterung der Shell-Parameter [Hervorhebung von mir] beschrieben:

Wenn der Parameter nicht gesetzt oder null ist , wird die Erweiterung des Wortes ersetzt. Andernfalls wird der Wert des Parameters ersetzt.

Wenn Sie einen Standardwert nur ersetzen möchten, wenn der Parameter nicht festgelegt ist (aber nicht, wenn er null ist, z. B. nicht, wenn es sich um eine leere Zeichenfolge handelt), verwenden Sie stattdessen diese Syntax:

somecommand ${1-foo}

Wieder aus dem Bash-Referenzhandbuch - 3.5.3 Erweiterung der Shell-Parameter :

Das Weglassen des Doppelpunkts führt zu einem Test nur für einen Parameter, der nicht festgelegt ist. Anders ausgedrückt, wenn der Doppelpunkt enthalten ist, prüft der Operator, ob beide Parameter vorhanden sind und ob ihr Wert nicht null ist. Wenn der Doppelpunkt weggelassen wird, prüft der Bediener nur die Existenz.

Itay Perl
quelle
52
Beachten Sie den semantischen Unterschied zwischen dem obigen Befehl "return fooif $1is aset oder eine leere Zeichenfolge " und ${1-foo}"return fooif $1is aset".
10b0
12
Können Sie erklären, warum das funktioniert? Was ist speziell die Funktion / der Zweck des ':' und '-'?
jwien001
8
@ jwein001: In der oben angegebenen Antwort wird ein Substitutionsoperator verwendet, um einen Standardwert zurückzugeben, wenn die Variable undefiniert ist. Insbesondere lautet die Logik "Wenn $ 1 existiert und nicht null ist, geben Sie seinen Wert zurück; andernfalls geben Sie foo zurück." Der Doppelpunkt ist optional. Wenn es weggelassen wird, ändern Sie "existiert und ist nicht null" in nur "existiert". Das Minuszeichen gibt an, dass foo zurückgegeben werden soll, ohne dass $ 1 gleich 'foo' gesetzt wird. Substitutionsoperatoren sind eine Unterklasse von Expansionsoperatoren. Siehe Abschnitt 6.1.2.1 von Robbins und Beebes Classic Shell Scripting [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles
5
@Jubbles oder wenn Sie nicht ein ganzes Buch für eine einfache Referenz kaufen möchten ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider
2
Diese Antwort wäre sogar noch besser, wenn sie zeigen würde, wie die Standardeinstellung als Ergebnis der Ausführung eines Befehls festgelegt wird, wie dies bei @hagen der Fall ist (obwohl diese Antwort unelegant ist).
Sautedman
310

Sie können einen Standardwert für eine Variable wie folgt festlegen:

somecommand.sh

#!/usr/bin/env bash

ARG1=${1:-foo}
ARG2=${2:-bar}
ARG3=${3:-1}
ARG4=${4:-$(date)}

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"

Hier einige Beispiele, wie dies funktioniert:

$ ./somecommand.sh
foo
bar
1
Thu Mar 29 10:03:20 ADT 2018

$ ./somecommand.sh ez
ez
bar
1
Thu Mar 29 10:03:40 ADT 2018

$ ./somecommand.sh able was i
able
was
i
Thu Mar 29 10:03:54 ADT 2018

$ ./somecommand.sh "able was i"
able was i
bar
1
Thu Mar 29 10:04:01 ADT 2018

$ ./somecommand.sh "able was i" super
able was i
super
1
Thu Mar 29 10:04:10 ADT 2018

$ ./somecommand.sh "" "super duper"
foo
super duper
1
Thu Mar 29 10:05:04 ADT 2018

$ ./somecommand.sh "" "super duper" hi you
foo
super duper
hi
you
Brad Parks
quelle
2
Ah, ok. Das hat -mich verwirrt (ist es negiert?).
Raffi Khatchadourian
5
Nein - das ist nur eine seltsame Art und Weise, wie Bash die Aufgabe erledigt. Ich werde noch einige Beispiele hinzufügen, um dies ein wenig zu verdeutlichen ... danke!
Brad Parks
44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi
Irit Katriel
quelle
1
Technisch gesehen, wenn Sie eine leere Zeichenfolge '' übergeben, die möglicherweise als Parameter zählt, Ihre Prüfung jedoch verfehlt. In diesem Fall würde $ # sagen, wie viele Parameter angegeben wurden
vmpstr
18
-nist das gleiche wie ! -z.
10b0
Ich erhalte unterschiedliche Ergebnisse mit -nund ! -zdaher würde ich sagen, dass dies hier nicht der Fall ist.
Elieser
Da Sie die Variable nicht angegeben haben, [ -n $1 ] ist dies immer der Fall . Wenn Sie bash verwenden, [[ -n $1 ]]wird sich so verhalten, wie Sie es erwarten, andernfalls müssen Sie zitieren[ -n "$1" ]
Glenn Jackman
21

Sie können die Anzahl der Argumente mit überprüfen $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi
Dennis
quelle
10

Bitte vergessen Sie nicht, wenn die Variable $ 1 .. $ n ist, müssen Sie in eine reguläre Variable schreiben, um die Substitution zu verwenden

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
hagen
quelle
2
Die obige Antwort von Brad beweist, dass Argumentvariablen auch ohne Zwischenvariablen ersetzt werden können.
Vadzim
2
+1 für die Angabe, wie ein Befehl wie Datum als Standard anstelle eines festen Werts verwendet werden kann. Dies ist auch möglich:DAY=${1:-$(date +%F -d "yesterday")}
Garren S
3

Für optionale Mehrfachargumente , analog zum lsBefehl, der eine oder mehrere Dateien aufnehmen kann, oder standardmäßig alles im aktuellen Verzeichnis auflistet:

if [ $# -ge 1 ]
then
    files="$@"
else
    files=*
fi
for f in $files
do
    echo "found $f"
done

Funktioniert leider nicht richtig für Dateien mit Leerzeichen im Pfad. Habe noch nicht herausgefunden, wie das funktioniert.

Jesse Glick
quelle
2

Dies ermöglicht den Standardwert für das optionale 1. Argument und behält mehrere Argumente bei.

 > cat mosh.sh
   set -- ${1:-xyz} ${@:2:$#} ; echo $*    
 > mosh.sh
   xyz
 > mosh.sh  1 2 3
   1 2 3 
mosh
quelle
1

Es ist möglich, die Variablensubstitution zu verwenden, dateum ein Argument durch einen festen Wert oder einen Befehl (wie ) zu ersetzen . Die Antworten haben sich bisher auf feste Werte konzentriert, aber dies ist, was ich verwendet habe, um Datum zu einem optionalen Argument zu machen:

~$ sh co.sh
2017-01-05

~$ sh co.sh 2017-01-04
2017-01-04

~$ cat co.sh

DAY=${1:-$(date +%F -d "yesterday")}
echo $DAY
Garren S.
quelle