Bash generuje błąd, wiersz 8: 1 $: zmienna niezwiązana

15

Próbuję nauczyć się korzystać z getopts, aby móc mieć skrypty z analizowanym wejściem (chociaż myślę, że getopts może być lepszy). Próbuję napisać prosty skrypt, aby zwrócić procent użycia partycji. Problem polega na tym, że jedna z moich funkcji bash nie wydaje się podobać, że odwołuję się $1jako zmienna w funkcji. Powodem, dla którego odwołam się, $1jest to, że do get_percentfunkcji można przekazać punkt montowania jako opcjonalny argument do wyświetlenia zamiast wszystkich punktów montowania.

Scenariusz

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

Wyjście

$ 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
źródło
Nie sądzę, żeby miało to coś wspólnego getopts, prawda? Twój skrypt kończy działanie z powodu -uprzed wywołaniem getopts.
ilkkachu
@ikkachu no Chyba nie. Ale nie jestem pewien, czy mogę teraz zmienić tytuł.
Timothy Pulliam
Pod postem powinien znajdować się mały tekst „edytuj”, tuż pod tagami w pytaniu
ilkkachu

Odpowiedzi:

29

set -uprzerwie dokładnie tak, jak opisano, jeśli odwołujesz się do zmiennej, która nie została ustawiona. Wywołujesz skrypt bez argumentów, więc get_percentjest wywoływany bez argumentów, co powoduje, że $1jest rozbrojony.

Sprawdź to przed wywołaniem funkcji lub użyj domyślnych rozszerzeń ( ${1-default}rozwinie się do, defaultjeśli nie jest już ustawione na coś innego).

DopeGhoti
źródło
Podejrzewałem to, ale nie mogłem wymyślić sposobu na obejście tego. Wydaje się, że domyślne rozszerzenie to naprawiło. Dziękuję Ci bardzo!
Timothy Pulliam
7
W szczególności można użyć [ -n "${1-}" ](czyli z pustą wartością domyślną), aby sprawdzić, czy parametr jest ustawiony i niepusty; lub [ "${1+x}" = x ]sprawdzić, czy jest ustawiony, nawet jeśli jest pusty.
ilkkachu
Nadal if [[ -n ${1-default} ]]
pojawia się
@ChaitanyaBapat Wciąż się poprawiałem, unbound variabledopóki nie użyłem :-zamiast -. Więc przynajmniej dla mnie ${1:-default}żaden samotnik nie podniósł błędu.
Adam Badura
6

To jest efekt set -u.

Możesz sprawdzić $#wewnątrz funkcji i uniknąć odwoływania się, $1jeśli nie jest ustawiona.

Dzięki $#możesz uzyskać dostęp do liczby parametrów. W kontekście globalnym jest to liczba parametrów skryptu, w funkcji jest to liczba parametrów funkcji.

Tak jest w kontekście pytania

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

Pamiętaj, że musisz użyć, [ $# -ge 1 ] && [ -n "$1" ]a nie [ $# -ge 1 -a -n "$1" ], ponieważ to najpierw ocenia, $1a następnie sprawdza $#.

RalfFriedl
źródło
Czy możesz wyjaśnić więcej, jak używać $ # i jak to sprawdzić? Dzięki
Chaitanya Bapat,
1
Dodałem przykład.
RalfFriedl,
3

Ponieważ jest bashto możliwe, możesz ominąć sprawdzenie, czy $1zostało ustawione i po prostu użyj "$@"( $1jest to pierwszy parametr, $@to wszystko; po podwójnym cudzysłowie znika całkowicie, jeśli nie ma żadnych wartości, co pozwala uniknąć jego złapania set -u):

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

Ulepszyłem też nieco resztę linii, aby nie wyświetlać {spacja} {tab} {spacja} między dwiema wartościami, które wypisujesz, ale zamiast tego otrzymujesz tylko {tab}. Jeśli naprawdę chcesz mieć dwie niewidoczne przestrzenie, zmień awkużycie printf "%s \t %s\n", $1, $5.

roaima
źródło
Będę musiał to sprawdzić. Nie znam tego typu zmiennej. Dzięki
Timothy Pulliam
@TimothyPulliam Dodałem krótkie wyjaśnienie $@dla ciebie
roaima