web-dev-qa-db-ja.com

Bashがエラーをスローする、8行目:$ 1:バインドされていない変数

Getoptsを使用して、入力を解析したスクリプトを作成できるようにする方法を学んでいます(ただし、getoptsの方が優れていると思います)。パーティションの使用率を返す簡単なスクリプトを作成しようとしています。問題は、bash関数の1つが、関数内の変数として$1を参照するのが好きではないようだということです。私が$1を参照する理由は、get_percent関数に、すべてのマウントポイントの代わりに、オプションの引数としてマウントポイントを渡して表示できるためです。

スクリプト

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

出力

$ 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は、設定されていない変数を参照すると、説明したとおりに中止されます。引数なしでスクリプトを呼び出しているので、get_percentは引数なしで呼び出されているため、$1を設定解除します。

関数を呼び出す前にこれを確認するか、デフォルトの展開(${1-default}defaultに展開されます(まだ他に設定されていない場合)。

29
DopeGhoti

これはset -uの影響です。

関数内で$#を確認し、設定されていない場合は$1を参照しないようにすることができます。

$#を使用すると、パラメーターの数にアクセスできます。グローバルコンテキストでは、スクリプトへのパラメーターの数です。関数では、関数へのパラメーターの数です。

質問の文脈では、それは

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

最初に[ $# -ge 1 ] && [ -n "$1" ]を評価してから[ $# -ge 1 -a -n "$1" ]をチェックするため、$1ではなく$#を使用する必要があることに注意してください。

6
RalfFriedl

これはbashであるため、$1が設定されているかどうかのチェックを回避し、"$@"を使用することができます($1は最初のパラメーター、$@はそれらすべてです;二重引用符で囲んだ場合、値がない場合は完全に表示されないため、set -uに捕捉されません。

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

また、出力する2つの値の間に{space} {tab} {space}が表示されず、{tab}しか表示されないように、残りの行を少し調整しました。 2つの非表示のスペースが本当に必要な場合は、awkを変更してprintf "%s \t %s\n", $1, $5を使用します。

3
roaima