Come scrivere uno script bash che accetta argomenti di input opzionali?


471

Voglio che il mio script sia in grado di accettare un input facoltativo,

ad esempio, attualmente la mia sceneggiatura è

#!/bin/bash
somecommand foo

ma vorrei che dicesse:

#!/bin/bash
somecommand  [ if $1 exists, $1, else, foo ]

3
Bash o POSIX? Con Bash ci sono più possibilità
user123444555621

@ Pumbaa80 bash - Ho aggiornato i tag.
Abe,


Risposte:


707

È possibile utilizzare la sintassi del valore predefinito:

somecommand ${1:-foo}

Quanto sopra, come descritto nel Manuale di riferimento di Bash - 3.5.3 Espansione dei parametri della shell [enfasi mia]:

Se il parametro non è impostato o è nullo , viene sostituita l'espansione della parola. Altrimenti, viene sostituito il valore del parametro.

Se si desidera sostituire un valore predefinito solo se il parametro non è impostato (ma non se è nullo, ad esempio se è una stringa vuota), utilizzare invece questa sintassi:

somecommand ${1-foo}

Sempre dal Manuale di riferimento di Bash - 3.5.3 Espansione dei parametri della shell :

Se si omettono i due punti si ottiene un test solo per un parametro non impostato. Detto in altro modo, se i due punti sono inclusi, l'operatore verifica l'esistenza di entrambi i parametri e che il suo valore non è nullo; se i due punti vengono omessi, l'operatore verifica solo l'esistenza.


53
Notare la differenza semantica tra il comando precedente, "return fooif $1is unsset o una stringa vuota " e ${1-foo}, "return fooif $1is unsset".
l0b0

12
Puoi spiegare perché funziona? In particolare, qual è la funzione / scopo di ":" e "-"?
jwien001,

8
@ jwein001: nella risposta inviata in precedenza, viene utilizzato un operatore di sostituzione per restituire un valore predefinito se la variabile non è definita. In particolare, la logica è "Se $ 1 esiste e non è nullo, restituisce il suo valore; altrimenti, restituisci pippo". I due punti sono opzionali. Se viene omesso, modifica "esiste e non è null" in "esiste solo". Il segno meno specifica di restituire foo senza impostare $ 1 uguale a 'foo'. Gli operatori di sostituzione sono una sottoclasse di operatori di espansione. Vedere la sezione 6.1.2.1 di Robbins and Beebe's Classic Shell Scripting [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles,

5
@Jubbles o se non vuoi acquistare un intero libro per un semplice riferimento ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider

2
Questa risposta sarebbe ancora migliore se mostrasse come rendere l'impostazione predefinita sia il risultato dell'esecuzione di un comando, come fa @hagen (sebbene quella risposta non sia elegante).
sautedman,

310

È possibile impostare un valore predefinito per una variabile in questo modo:

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"

Ecco alcuni esempi di come funziona:

$ ./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

2
Ah ok. -L'avermi confuso (è negato?).
Raffi Khatchadourian,

5
No - è solo un modo strano che bash ha di fare l'incarico. Aggiungerò altri esempi per chiarire un po 'questo ... grazie!
Brad Parks,

44
if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi

1
Tecnicamente, se passi una stringa vuota '' che può essere considerata un parametro, ma il tuo controllo lo mancherà. In tal caso $ # direbbe quanti parametri sono stati forniti
vmpstr

18
-nè lo stesso di ! -z.
l0b0

Ottengo risultati diversi usando -ne ! -zquindi direi che non è il caso qui.
Eliezer,

perché non hai citato la variabile, [ -n $1 ] sarà sempre vero . Se usi bash, [[ -n $1 ]]si comporterà come ti aspetti, altrimenti dovrai citare[ -n "$1" ]
glenn jackman il

21

Puoi controllare il numero di argomenti con $#

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

10

per favore non dimenticare, se la sua variabile $ 1 .. $ n è necessario scrivere in una variabile normale per utilizzare la sostituzione

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}

2
La risposta di Brad sopra dimostra che le variabili di argomento possono anche essere sostituite senza variazioni intermedie.
Vadzim,

2
+1 per notare come usare un comando come date come predefinito invece che come valore fisso. Questo è anche possibile:DAY=${1:-$(date +%F -d "yesterday")}
Garren S

3

Per argomenti multipli opzionali , per analogia con il lscomando che può prendere uno o più file o di default elenca tutto nella directory corrente:

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

Non funziona correttamente per i file con spazi nel percorso, ahimè. Non ho ancora capito come farlo.


2

Ciò consente il valore predefinito per il 1o argomento opzionale e preserva più argomenti.

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

1

È possibile utilizzare la sostituzione variabile per sostituire un valore fisso o un comando (come date) per un argomento. Le risposte finora si sono concentrate su valori fissi, ma questo è quello che ho usato per rendere la data un argomento facoltativo:

~$ 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.