Bash renvoie une erreur, ligne 8: $ 1: variable non liée

15

J'essaie d'apprendre à utiliser getopts pour pouvoir avoir des scripts avec une entrée analysée (bien que je pense que getopts pourrait être mieux). J'essaie simplement d'écrire un script simple pour renvoyer les pourcentages d'utilisation de la partition. Le problème est qu'une de mes fonctions bash ne semble pas aimer celle que je référence $1comme variable dans la fonction. La raison pour laquelle je fais référence $1est que la get_percentfonction peut recevoir un point de montage comme argument facultatif à afficher à la place de tous les points de montage.

Le scénario

#!/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
# ...

Le résultat

$ 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
la source
Je ne pense pas que cela ait quelque chose à voir getopts, n'est-ce pas? Votre script se ferme -uavant d'appeler getopts.
ilkkachu
@ikkachu non, je suppose que non. Mais je ne suis pas sûr de pouvoir changer le titre maintenant.
Timothy Pulliam
Il devrait y avoir ce petit texte "modifier" sous le message, juste sous les balises dans une question
ilkkachu

Réponses:

29

set -us'interrompra exactement comme vous le décrivez si vous faites référence à une variable qui n'a pas été définie. Vous invoquez votre script sans arguments, donc vous êtes get_percentinvoqué sans arguments, ce $1qui entraîne sa non-définition.

Vérifiez cela avant d'appeler votre fonction, ou utilisez des extensions par défaut ( ${1-default}seront développées defaultsi elles ne sont pas déjà définies sur autre chose).

DopeGhoti
la source
Je m'en doutais, mais je ne pouvais pas trouver de solution. L'expansion par défaut semble l'avoir corrigé. Merci beaucoup!
Timothy Pulliam
7
En particulier, on pourrait utiliser [ -n "${1-}" ](c'est-à-dire avec une valeur par défaut vide) pour voir si le paramètre est défini et non vide; ou [ "${1+x}" = x ]pour voir s'il est défini, même s'il est vide.
ilkkachu du
J'obtiens toujours une erreur de variable non liée malgré l'utilisationif [[ -n ${1-default} ]]
Chaitanya Bapat
6

C'est l'effet de set -u.

Vous pouvez vérifier l' $#intérieur de la fonction et éviter de faire référence $1si elle n'est pas définie.

Avec $#vous pouvez accéder au nombre de paramètres. Dans le contexte global, c'est le nombre de paramètres du script, dans une fonction, c'est le nombre de paramètres de la fonction.

Dans le cadre de la question, il est

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

Notez que vous devez utiliser [ $# -ge 1 ] && [ -n "$1" ]et non [ $# -ge 1 -a -n "$1" ], car cela évaluerait d'abord $1, puis vérifierait $#.

RalfFriedl
la source
Pouvez-vous expliquer comment utiliser $ # et comment le vérifier? Merci
Chaitanya Bapat
1
J'ai ajouté un exemple.
RalfFriedl
3

Puisqu'il s'agit de cela, bashvous pouvez contourner la vérification pour $1être défini et simplement l'utiliser "$@"( $1est le premier paramètre, $@est tous; lorsqu'il est placé entre deux guillemets, il disparaît complètement s'il n'a pas de valeurs, ce qui évite qu'il ne soit détecté set -u):

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

J'ai également légèrement modifié le reste de la ligne afin que vous n'obteniez pas {espace} {tab} {espace} entre les deux valeurs que vous affichez mais que vous n'obteniez qu'un {tab}. Si vous voulez vraiment les deux espaces invisibles, changez le awkà utiliser printf "%s \t %s\n", $1, $5.

roaima
la source
Je vais devoir examiner cela. Je ne connais pas ce type de variable. Merci
Timothy Pulliam
@TimothyPulliam J'ai ajouté une brève explication $@pour vous
roaima