web-dev-qa-db-ja.com

関数を使用して、設定されていないBash変数をテストする

簡単なBash変数テストは次のとおりです。

${varName:?    "${varName} is not defined"}

これを関数に入れて再利用したい。どう?

フォロー失敗

#
# Test a variable exists
tvar(){
 val=${1:?    "${1}    must be defined, preferably in $basedir"}
 if [ -z ${val}  ]
     then 
     echo Zero length value 
 else
     echo ${1} exists, value ${1}
 fi
}

つまりテストが失敗した場合は、終了する必要があります。

28
DaveP

lhunath'sのおかげで、私は何百回も見過ごしてきたBash manページの一部に導かれました。

サブストリング展開を実行しない場合、bashは
が設定されていないかnullであるパラメーターをテストします。コロンを省略すると、設定されていないパラメータ
のみがテストされます。

これにより、次の真理値表を作成するよう求められました。

 
 |設定解除|セット|セットと|意味
 | |でもnull | nullではない| 
 ============ + ======= + ========== + ========== + ============================= 
 $ {var-_} | T | F | T |非ヌルまたは未設定
 ------------ + ------- + ---------- + -------- -+ ----------------------------- 
 $ {var:-_} | T | T | T |常にtrue、substに使用します。
 ------------ + ------- + ---------- + ------ ---- + ----------------------------- 
 $ var | F | F | T | varが設定され、nullではない
 ------------ + ------- + ---------- + ------- --- + ----------------------------- 
 $ {!var [@]} | F | T | T |変数が設定されています
 

この表は、最後の行の仕様を紹介しています。 Bash manページには、「名前が配列でない場合、名前が設定されている場合は0に展開され、それ以外の場合はnullに展開されます」と表示されます。この真理値表では、配列であっても同じように動作します。

46

あなたが探しているのは間接的です。

assertNotEmpty() {
    : "${!1:? "$1 is empty, aborting."}"
}

このため、次のような場合、スクリプトはエラーメッセージを表示して中止されます。

$ foo=""
$ assertNotEmpty foo
bash: !1:  foo is empty, aborting.

testfooが空であるかどうかだけを望む場合は、スクリプトを中止する代わりに、関数の代わりにこれを使用します。

[[ $foo ]]

例えば:

until read -p "What is your name? " name && [[ $name ]]; do
    echo "You didn't enter your name.  Please, try again." >&2
done

また、未設定パラメータの間に非常に重要な違いがあることに注意してください。これらの用語を混同しないように注意してください!空のパラメータは、設定されているが空の文字列に設定されているだけのパラメータです。未設定のパラメーターは、まったく存在しないパラメーターです。

前の例はすべてemptyパラメータをテストしています。 nsetパラメータをテストし、設定されたすべてのパラメータが空であるかどうかを検討する場合は、それらが空かどうかにかかわらず、次のように使用します。

[[ ! $foo && ${foo-_} ]]

次のような関数で使用します。

assertIsSet() {
    [[ ! ${!1} && ${!1-_} ]] && {
        echo "$1 is not set, aborting." >&2
        exit 1
    }
}

渡したパラメーター名が設定されていないパラメーターを示している場合にのみスクリプトを中止します。

$ ( foo="blah"; assertIsSet foo; echo "Still running." )
Still running.
$ ( foo=""; assertIsSet foo; echo "Still running." )
Still running.
$ ( unset foo; assertIsSet foo; echo "Still running." )
foo is not set, aborting.
19
lhunath

[ -z ${parameter+Word} ]を使用したい

man bashの一部:

Parameter Expansion
    ...
    In  each  of  the cases below, Word is subject to tilde expansion, parameter expansion, command substitution, and
    arithmetic expansion.  When not performing substring expansion, bash tests for a parameter that is unset or null;
    omitting the colon results in a test only for a parameter that is unset.
    ...
    ${parameter:+Word}
           Use Alternate Value.  If parameter is null or unset, nothing is substituted, otherwise  the  expansion  of
           Word is substituted.
    ...

言い換えると:

    ${parameter+Word}
           Use Alternate Value.  If parameter is unset, nothing is substituted, otherwise  the  expansion  of
           Word is substituted.

いくつかの例:

$ set | grep FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
it is unset
$ declare FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ FOOBAR=
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ FOOBAR=1
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
$ unset FOOBAR
$ if [ -z "${FOOBAR+something}" ]; then echo "it is unset"; fi
it is unset
$
5
dnozay

この関数は、現在設定されている変数をテストします。変数は配列でもかまいません。 bashでは、0 == TRUE、1 == FALSEであることに注意してください。

function var.defined {
    eval '[[ ${!'$1'[@]} ]]'
}

# Typical Usage of var.defined {}

declare you="Your Name Here" ref='you';

read -p "What's your name: " you;

if var.defined you; then   # Simple demo using literal text

    echo "BASH recognizes $you";
    echo "BASH also knows a reference to $ref as ${!ref}, by indirection."; 

fi

unset you # have just been killed by a master :D

if ! var.defined $ref; then    # Standard demo using an expanded literal value

    echo "BASH doesn't know $ref any longer";

fi

read -s -N 1 -p "Press any key to continue...";
echo "";

ここで明確にするために、関数はリテラルテキストをテストします。コマンドがbashで呼び出されるたびに、以下の場合を除いて、変数は一般に、基本的な値で「スワップアウト」または「置換」されます。

  • $ varRef($)はエスケープされます:\ $ varRef
  • $ varRefは単一引用符で囲まれた '$ varRef'です
3
user735796

これがまさにあなたが望むものであるかどうかはわかりませんが、新しい+複雑なスクリプトを書くときに私が使用する便利なトリックは "set -o"を使用することです

set -o#設定されていない変数を検出すると、スクリプトを爆弾にします

例えば:

$ grep '$ 1' chex.sh

ケース「$ 1」

$ ./chex.sh

./chex.sh:111行目:$ 1:バインドされていない変数

$ ./chex.sh foo

正しくない/オプションが渡されていません。終了します

1
user381689

私はあなたが何が必要かを正確に理解していません。これにもかかわらず私はあなたに返信しようとしています。

つまりテストが失敗した場合は、終了する必要があります。

コード:

${varName:?    "${varName} is not defined"}

「varName」という名前の変数がない場合、ゼロ以外の終了コードを返します。最後のコマンドの終了コードは$?に保存されます。

コードについて:

val=${1:?    "${1}    must be defined, preferably in $basedir"}

多分それはあなたが必要としていることをしていません。 $1が定義されていない場合、"${1}"は何も置換されません。おそらく、置換せずに文字どおり${1}を書く単一引用符を使用したいでしょう。

val=${1:?    '${1}    must be defined, preferably in $basedir'
1
Andrea Francia
if set | grep -q '^VARIABLE='
then 
    echo VARIABLE is set
fi
0
Emery Lapinski