Bash arroja error, línea 8: $ 1: variable independiente

15

Estoy tratando de aprender a usar getopts para poder tener scripts con entrada analizada (aunque creo que getopts podría ser mejor). Estoy tratando de escribir un script simple para devolver porcentajes de uso de la partición. El problema es que a una de mis funciones bash no parece gustarle que haga referencia $1como una variable dentro de la función. La razón por la que hago referencia $1es porque a la get_percentfunción se le puede pasar un punto de montaje como un argumento opcional para mostrar en lugar de todos los puntos de montaje.

La secuencia de comandos

#!/usr/bin/bash

set -e
set -u
set -o pipefail

get_percent(){
    if [ -n "$1" ] 
    then
        df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
    else
        df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
    fi
}

usage(){
    echo "script usage: $(basename $0) [-h] [-p] [-m mount_point]" >&2
}

# If the user doesn't supply any arguments, we run the script as normal
if [ $# -eq 0 ];
then
    get_percent
    exit 0
fi
# ...

La salida

$ bash thing.sh
thing.sh: line 8: $1: unbound variable

$ bash -x thing.sh
+ set -e
+ set -u
+ set -o pipefail
+ '[' 0 -eq 0 ']'
+ get_percent
thing.sh: line 8: $1: unbound variable
Timothy Pulliam
fuente
No creo que esto tenga nada que ver getopts, ¿verdad? Su script se cierra debido a -uantes de llamar getopts.
ilkkachu
@ikkachu no, supongo que no. Pero no estoy seguro de poder cambiar el título ahora.
Timothy Pulliam
Debería haber ese pequeño texto de "edición" debajo de la publicación, justo debajo de las etiquetas en una pregunta
ilkkachu

Respuestas:

29

set -uabortará exactamente como lo describe si hace referencia a una variable que no se ha establecido. Invoca su script sin argumentos, por lo que get_percentse invoca sin argumentos, lo $1que hace que se desarme.

Verifique esto antes de invocar su función, o use expansiones predeterminadas ( ${1-default}se expandirá a defaultsi no está configurado en otra cosa).

DopeGhoti
fuente
Sospeché esto, pero no podía pensar en una forma de evitarlo. La expansión predeterminada parece haberlo solucionado. ¡Muchas gracias!
Timothy Pulliam
77
En particular, se podría usar [ -n "${1-}" ](es decir, con un valor predeterminado vacío) para ver si el parámetro está configurado y no está vacío; o [ "${1+x}" = x ]para ver si está configurado, incluso si está vacío.
ilkkachu
Todavía recibo un error de variable independiente a pesar de usarif [[ -n ${1-default} ]]
Chaitanya Bapat
6

Este es el efecto de set -u.

Puede verificar $#dentro de la función y evitar hacer referencia $1si no está configurada.

Con $#usted puede acceder a la cantidad de parámetros. En el contexto global es el número de parámetros para el script, en una función es el número de parámetros para la función.

En el contexto de la pregunta, es

if [ $# -ge 1 ] && [ -n "$1" ]
then
    df -h $1 | tail -n +2 | awk '{ print $1,"\t",$5 }'
else
    df -h | tail -n +2 | awk '{ print $1,"\t",$5 }'
fi

Tenga en cuenta que debe usar [ $# -ge 1 ] && [ -n "$1" ]y no [ $# -ge 1 -a -n "$1" ], porque eso primero evaluaría $1y luego comprobaría $#.

RalfFriedl
fuente
¿Puede explicar más cómo usar $ # y cómo verificarlo? Gracias
Chaitanya Bapat el
1
Agregué un ejemplo.
RalfFriedl
3

Como es bashasí, puede eludir la verificación para $1establecerlo y simplemente usarlo "$@"( $1es el primer parámetro, $@son todos; cuando se cita doblemente, desaparece por completo si no tiene valores, lo que evita que sea atrapado set -u):

get_percent() {
    df -h "$@" | awk 'NR>1 { printf "%s\t%s\n", $1, $5 }'
}

También he ajustado ligeramente el resto de la línea para que no obtenga {space} {tab} {space} entre los dos valores que genera, pero inserte solo obtenga una {tab}. Si realmente quiere los dos espacios invisibles, cambie el awkuso printf "%s \t %s\n", $1, $5.

roaima
fuente
Tendré que investigar esto. No estoy familiarizado con ese tipo de variable. Gracias
Timothy Pulliam
@TimothyPulliam He añadido una breve explicación de $@por ti
roaima