¿Cómo escribir un script bash que tome argumentos de entrada opcionales?


471

Quiero que mi script pueda tomar una entrada opcional,

por ejemplo, actualmente mi script es

#!/bin/bash
somecommand foo

pero me gustaría que dijera:

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

3
Bash o POSIX? Con Bash, hay más posibilidades
usuario123444555621

@ Pumbaa80 bash - He actualizado las etiquetas.
Abe


Respuestas:


707

Puede usar la sintaxis de valor predeterminado:

somecommand ${1:-foo}

Lo anterior, como se describe en el Manual de referencia de Bash - 3.5.3 Expansión del parámetro Shell [énfasis mío]:

Si el parámetro no está establecido o es nulo , la expansión de la palabra se sustituye. De lo contrario, el valor del parámetro se sustituye.

Si solo desea sustituir un valor predeterminado si el parámetro no está establecido (pero no si es nulo, por ejemplo, si es una cadena vacía), utilice esta sintaxis en su lugar:

somecommand ${1-foo}

Nuevamente del Manual de referencia de Bash - 3.5.3 Expansión del parámetro Shell :

Omitir los dos puntos da como resultado una prueba solo para un parámetro que no está establecido. Dicho de otra manera, si se incluyen los dos puntos, el operador comprueba la existencia de ambos parámetros y que su valor no es nulo; si se omiten los dos puntos, el operador solo prueba la existencia.


53
Tenga en cuenta la diferencia semántica entre el comando anterior, "devolver foosi no $1está configurado o una cadena vacía " y ${1-foo}"devolver foosi no $1está configurado".
l0b0

12
¿Puedes explicar por qué esto funciona? Especialmente, ¿cuál es la función / propósito de ':' y '-'?
jwien001

8
@ jwein001: en la respuesta presentada anteriormente, se utiliza un operador de sustitución para devolver un valor predeterminado si la variable no está definida. Específicamente, la lógica es "Si $ 1 existe y no es nulo, devuelve su valor; de lo contrario, devuelve foo". El colon es opcional. Si se omite, el cambio "existe y no es nulo" a solo "existe". El signo menos especifica devolver foo sin establecer $ 1 igual a 'foo'. Los operadores de sustitución son una subclase de operadores de expansión. Consulte la sección 6.1.2.1 de Robbins and Beebe's Classic Shell Scripting [O'Reilly] ( shop.oreilly.com/product/9780596005955.do )
Jubbles el

55
@Jubbles o si no quieres comprar un libro completo para una simple referencia ... tldp.org/LDP/abs/html/parameter-substitution.html
Ohad Schneider

2
Esta respuesta sería aún mejor si mostrara cómo hacer que el valor predeterminado sea el resultado de ejecutar un comando, como lo hace @hagen (aunque esa respuesta es poco elegante).
salteado

310

Puede establecer un valor predeterminado para una variable así:

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"

Aquí hay algunos ejemplos de cómo funciona esto:

$ ./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 El -me confundió (¿se niega?).
Raffi Khatchadourian

55
No, esa es solo una forma extraña que bash tiene de hacer la tarea. Agregaré algunos ejemplos más para aclarar esto un poco ... ¡gracias!
Brad Parks el

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

1
Técnicamente, si pasa una cadena vacía '', eso podría contar como un parámetro, pero su verificación lo perderá. En ese caso, $ # diría cuántos parámetros se dieron
vmpstr

18
-nes el mismo que ! -z.
l0b0

Consigo diferentes resultados utilizando -ny ! -zasí que diría que no es el caso aquí.
Eliezer

porque no pudo citar la variable, [ -n $1 ] siempre será cierto . Si usa bash, [[ -n $1 ]]se comportará como espera, de lo contrario debe citarlo[ -n "$1" ]
glenn jackman

21

Puede verificar el número de argumentos con $#

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

10

por favor no olvides, si su variable $ 1 .. $ n necesitas escribir en una variable regular para usar la sustitución

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

2
La respuesta de Brad anterior prueba que las variables de argumento también se pueden sustituir sin variables intermedias.
Vadzim

2
+1 por señalar la forma de usar un comando como fecha como predeterminado en lugar de un valor fijo. Esto también es posible:DAY=${1:-$(date +%F -d "yesterday")}
Garren S

3

Para argumentos múltiples opcionales , por analogía con el lscomando que puede tomar uno o más archivos o, por defecto, enumera todo en el directorio actual:

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

No funciona correctamente para archivos con espacios en la ruta, por desgracia. Todavía no he descubierto cómo hacer que eso funcione.


2

Esto permite el valor predeterminado para el 1er argumento opcional, y conserva múltiples argumentos.

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

1

Es posible utilizar la sustitución de variables para sustituir un valor fijo o un comando (como date) para un argumento. Las respuestas hasta ahora se han centrado en valores fijos, pero esto es lo que solía hacer de la fecha un argumento opcional:

~$ 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.