Bash, advertencia sin argumentos y decisiones de casos

110

Estoy aprendiendo bash.

Me gustaría hacer un script simple que, cuando no se dan argumentos, muestra algún mensaje. Y cuando doy números como argumento, s dependiendo del valor, hace una cosa u otra.

También me gustaría conocer sugerencias de los mejores manuales en línea para principiantes en bash

Gracias

Abre el camino
fuente

Respuestas:

176
if [[ $# -eq 0 ]] ; then
    echo 'some message'
    exit 0
fi

case "$1" in
    1) echo 'you gave 1' ;;
    *) echo 'you gave something else' ;;
esac

La Advanced Bash-Scripting Guide es bastante buena. A pesar de su nombre, trata lo básico.

Thomas
fuente
RE: "salida 0". No sé si salir del guión era lo que tenía en mente. Pero sí, es una guía excelente.
Trampas Kirk
Interpreté "y" como "lo contrario", asumiendo que el mensaje sería un texto de ayuda. Pero estoy seguro de que Werner puede descubrir qué hace esa línea y si la quiere :)
Thomas
gracias, por supuesto! y por último, ¿cómo puedo desactivar los mensajes de error del script para que no se muestren en el shell?
Abre el camino el
¿Te refieres a los errores que surgen de un programa en particular al que estás llamando? Puede poner > /dev/nully / o 2> /dev/nulldespués de eso enviar su salida estándar y / o flujos de error estándar al olvido.
Thomas
4
Si considera que falta un argumento como algo malo (como que el script no puede funcionar correctamente), devuelva algo diferente a 0 ( exit 1). Existen otras convenciones sobre códigos de retorno / salida, que puede encontrar en línea rápidamente, pero el punto importante es que no debe ser 0, lo que indica éxito.
Felix
25

Si solo está interesado en rescatar si falta un argumento en particular, la sustitución de parámetros es excelente:

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT
Palmadita
fuente
11

Ejemplo

 if [ -z "$*" ]; then echo "No args"; fi

Resultado

No args

Detalles

-z es el operador unario para la longitud de la cadena es cero. $*son todos los argumentos. Las comillas son por seguridad y encapsulan múltiples argumentos si están presentes.

Utilice man bashy busque ( tecla / ) "unario" para más operadores como este.

Trampas Kirk
fuente
7
Un problema (menor) con esto es que no distingue entre no pasar argumentos y pasar una cadena vacía como argumento. Eso puede ser importante en algunos contextos. Usando [$ # -eq 0] uno puede manejar ambos casos correctamente.
Idelic
1
Ah, las sutilezas de la programación (ba) sh ... Por eso la odio.
Thomas
1
pensar en -zcomo mizzing
Ray Foss
4

Viejo, pero tengo motivos para volver a trabajar la respuesta ahora gracias a una confusión previa:

if [[ $1 == "" ]] #Where "$1" is the positional argument you want to validate 

 then
 echo "something"
 exit 0

fi

Esto hará eco de "Algo" si no hay un argumento posicional $ 1. Sin embargo, no valida que $ 1 contenga información específica.

Ryan Smith
fuente
$#es explícitamente el recuento entero del número de argumentos; será "0", y repetirá "algo" aunque no haya argumentos, o será un número positivo, y repetirá "algo" correctamente. Pero la verificación en sí nunca hará nada, independientemente de la entrada o la falta de entrada que use; siempre informará que $#contiene un valor. Entonces esto es completamente incorrecto y nunca funcionará como se afirma.
eschwartz
¿Estás completamente seguro de eso? Tengo varios scripts que funcionan según lo previsto con este formato exacto. Al leer su respuesta, incluso volví a probar tanto por el partido como por la falta del mismo. $ # no contendrá un valor si no se especifica, si no hay un argumento posicional que coincida con lo que sea # en su escenario. No tiene sentido por qué bash asumiría un valor en un argumento posicional que no está allí.
Ryan Smith
Pruebe echo $#como el contenido de un script /tmp/test.sh, luego ejecútelo en / bin / bash así como en / bin / sh (o / bin / dash y cualquier otra implementación de shell que tenga disponible. /tmp/test.shRepetirá "0" para la consola, como lo hará /bin/dash /tmp/test.sh. Por otro lado, /tmp/test.sh foohará eco de "1", y /tmp/test.sh first secondhará eco de "2".
eschwartz
Según man bash, en la sección "Parámetros especiales", "El shell trata varios parámetros de manera especial. Estos parámetros solo pueden ser referenciados; no se permite su asignación", y "# Se expande al número de parámetros posicionales en decimal". También es un mandato de POSIX como se describe en pubs.opengroup.org/onlinepubs/9699919799/utilities/…
eschwartz
Lo siento, parece que hubo una falta de comunicación. Quise decir # como marcador de posición para el argumento posicional específico (es decir, $ 2 si se refería al segundo argumento) no literal $ #. Después de revisar lo anterior, está absolutamente en lo cierto, un $ # literal siempre se resolverá con el número de argumentos. Disculpas por la confusión.
Ryan Smith