Comment écrire un script bash qui accepte des arguments d'entrée facultatifs?

471

Je veux que mon script puisse prendre une entrée facultative,

par exemple, actuellement mon script est

#!/bin/bash
somecommand foo

mais je voudrais qu'il dise:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]
Abe
la source
3
Bash ou POSIX? Avec Bash, il y a plus de possibilités
user123444555621
@ Pumbaa80 bash - J'ai mis à jour les balises.
Abe

Réponses:

707

Vous pouvez utiliser la syntaxe de valeur par défaut:

somecommand ${1:-foo}

Comme décrit dans le Manuel de référence Bash - 3.5.3 Expansion des paramètres du shell [accentuation], les éléments ci-dessus :

Si le paramètre est non défini ou nul , l'expansion du mot est substituée. Sinon, la valeur du paramètre est substituée.

Si vous ne souhaitez remplacer une valeur par défaut que si le paramètre n'est pas défini (mais pas s'il est nul, par exemple pas s'il s'agit d'une chaîne vide), utilisez plutôt cette syntaxe:

somecommand ${1-foo}

Encore une fois dans le manuel de référence Bash - 3.5.3 Expansion des paramètres du shell :

L'omission des deux points entraîne un test uniquement pour un paramètre non défini. Autrement dit, si le signe deux-points est inclus, l'opérateur teste l'existence des deux paramètres et leur valeur n'est pas nulle; si le signe deux-points est omis, l'opérateur teste uniquement l'existence.

Itay Perl
la source
53
Veuillez noter la différence sémantique entre la commande ci-dessus, "return fooif $1is unset or a empty string ", and ${1-foo}, "return fooif $1is unset".
l0b0
12
Pouvez-vous expliquer pourquoi cela fonctionne? En particulier, quelle est la fonction / le but des ':' et '-'?
jwien001
8
@ jwein001: Dans la réponse soumise ci-dessus, un opérateur de substitution est utilisé pour renvoyer une valeur par défaut si la variable n'est pas définie. Plus précisément, la logique est "Si $ 1 existe et n'est pas nul, retourne sa valeur; sinon, retourne foo." Le deux-points est facultatif. S'il est omis, remplacez "existe et n'est pas nul" par "existe" uniquement. Le signe moins spécifie de retourner foo sans définir $ 1 égal à 'foo'. Les opérateurs de substitution sont une sous-classe d'opérateurs d'expansion. Voir la section 6.1.2.1 de Robbins and Beebe's Classic Shell Scripting [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles
5
@Jubbles ou si vous ne voulez pas acheter un livre entier pour une simple référence ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider
2
Cette réponse serait encore meilleure si elle montrait comment faire de la valeur par défaut le résultat de l'exécution d'une commande, comme le fait @hagen (bien que cette réponse ne soit pas élégante).
sautedman
310

Vous pouvez définir une valeur par défaut pour une variable comme ceci:

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"

Voici quelques exemples de comment cela fonctionne:

$ ./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
la source
2
Ah ok. Le -m'a confondu (est-ce nié?).
Raffi Khatchadourian
5
Non - c'est juste une façon étrange pour Bash de faire le devoir. Je vais ajouter quelques exemples pour clarifier un peu cela ... merci!
Brad Parks
44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi
Irit Katriel
la source
1
Techniquement, si vous passez une chaîne vide '', cela pourrait compter comme paramètre, mais votre vérification le manquera. Dans ce cas, $ # dirait combien de paramètres ont été donnés
vmpstr
18
-nest le même que ! -z.
l0b0
J'obtiens des résultats différents en utilisant -net ! -zdonc je dirais que ce n'est pas le cas ici.
Eliezer
parce que vous n'avez pas cité la variable, ce [ -n $1 ] sera toujours vrai . Si vous utilisez bash, [[ -n $1 ]]se comportera comme prévu, sinon vous devez citer[ -n "$1" ]
glenn jackman
21

Vous pouvez vérifier le nombre d'arguments avec $#

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

n'oubliez pas, si sa variable $ 1 .. $ n vous devez écrire dans une variable régulière pour utiliser la substitution

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
hagen
la source
2
La réponse de Brad ci-dessus prouve que les variables d'argument peuvent également être remplacées sans variables intermédiaires.
Vadzim
2
+1 pour avoir noté la manière d'utiliser une commande comme date comme valeur par défaut au lieu d'une valeur fixe. C'est aussi possible:DAY=${1:-$(date +%F -d "yesterday")}
Garren S
3

Pour les arguments multiples optionnels , par analogie avec la lscommande qui peut prendre un ou plusieurs fichiers ou par défaut liste tout dans le répertoire courant:

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

Hélas, ne fonctionne pas correctement pour les fichiers avec des espaces dans le chemin. Je n'ai pas encore trouvé comment faire fonctionner cela.

Jesse Glick
la source
2

Cela permet la valeur par défaut du 1er argument optionnel et préserve plusieurs arguments.

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

Il est possible d'utiliser la substitution de variable pour substituer une valeur fixe ou une commande (comme date) à un argument. Jusqu'à présent, les réponses se sont concentrées sur des valeurs fixes, mais c'est ce que j'ai utilisé pour faire de la date un argument facultatif:

~$ 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
la source