web-dev-qa-db-fra.com

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

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 que je fasse référence à $1 En tant que variable dans la fonction. La raison pour laquelle je référence $1 Est parce que la fonction get_percent 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
15
Timothy Pulliam

set -u s'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 argument, donc get_percent est appelé sans argument, provoquant $1 à désactiver.

Vérifiez cela avant d'appeler votre fonction ou utilisez des extensions par défaut (${1-default} sera étendu à default s'il n'est pas déjà défini sur autre chose).

29
DopeGhoti

C'est l'effet de set -u.

Vous pouvez vérifier $# à l'intérieur de la fonction et évitez de référencer $1 s'il n'est pas défini.

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 pas [ $# -ge 1 -a -n "$1" ], car cela évaluerait d'abord $1 puis vérifiez $#.

6
RalfFriedl

Comme il s'agit de bash, vous pouvez contourner la vérification de $1 en cours de définition et utilisez simplement "$@" ($1 est le premier paramètre, $@ est tous; lorsqu'il est entre guillemets, il disparaît complètement s'il n'a pas de valeurs, ce qui évite qu'il ne soit pris par 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 produisez, mais que vous n'obteniez qu'un {tab}. Si vous voulez vraiment les deux espaces invisibles, changez le awk pour utiliser printf "%s \t %s\n", $1, $5.

3
roaima