Bashで長さがゼロでない文字列をテストします:[-n“ $ var”]または[“ $ var”]


182

Bashスクリプトが長さ0以外の文字列を2つの異なる方法でテストするのを見てきました。ほとんどのスクリプトは-nオプションを使用します:

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

ただし、-nオプションは実際には必要ありません。

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

どちらが良い方法ですか?

同様に、これは長さゼロをテストするためのより良い方法です:

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

または

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi

回答:


394

編集:これは、[(別名test)との違いを示す、より完全なバージョンです[[

次の表は、変数が引用符で囲まれているかどうか、単一または二重の角かっこを使用しているかどうか、変数にスペースのみが含まれているかどうかが、変数の-n/-zチェックに適しているかどうかのテストの使用が変数のチェックに適していることを示しています。

     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b
     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"
-----+------------------------------------+------------------------------------
unset| false false true  false true  true | false false false false true  true
null | false false true  false true  true | false false false false true  true
space| false true  true  true  true  false| true  true  true  true  false false
zero | true  true  true  true  false false| true  true  true  true  false false
digit| true  true  true  true  false false| true  true  true  true  false false
char | true  true  true  true  false false| true  true  true  true  false false
hyphn| true  true  true  true  false false| true  true  true  true  false false
two  | -err- true  -err- true  -err- false| true  true  true  true  false false
part | -err- true  -err- true  -err- false| true  true  true  true  false false
Tstr | true  true  -err- true  -err- false| true  true  true  true  false false
Fsym | false true  -err- true  -err- false| true  true  true  true  false false
T=   | true  true  -err- true  -err- false| true  true  true  true  false false
F=   | false true  -err- true  -err- false| true  true  true  true  false false
T!=  | true  true  -err- true  -err- false| true  true  true  true  false false
F!=  | false true  -err- true  -err- false| true  true  true  true  false false
Teq  | true  true  -err- true  -err- false| true  true  true  true  false false
Feq  | false true  -err- true  -err- false| true  true  true  true  false false
Tne  | true  true  -err- true  -err- false| true  true  true  true  false false
Fne  | false true  -err- true  -err- false| true  true  true  true  false false

変数の長さがゼロでないかどうかを知りたい場合は、次のいずれかを実行します。

  • 変数を単一の括弧で囲みます(列2a)
  • -n変数を単一の括弧で囲んで使用します(列4a)
  • 二重括弧を引用符付きまたはなしで、または引用符なしで使用します-n(列1b-4b)

「2」とラベル付けされた行から始まる列1aで、結果が変数[内容を条件式の一部であるかのように評価していることを示すことに注意してください(結果は、「T」または「F」によって暗示されるアサーションと一致説明の列)。[[が使用される場合(列1b)、変数の内容は文字列と見なされ、評価されません。

列3aと5aのエラーは、変数値にスペースが含まれ、変数が引用符で囲まれていないために発生します。ここでも、列3bおよび5bに示すように[[、変数の内容を文字列として評価します。

これに対応して、長さがゼロの文字列のテストでは、列6a、5b、6bが正しい方法を示しています。また、否定が反対の操作を使用するよりも明確な意図を示している場合、これらのテストのいずれも否定できることに注意してください。例:if ! [[ -n $var ]]

を使用している場合[、予期しない結果が発生しないようにするための鍵は、変数を引用することです。を使用[[しても問題ありません。

抑制されているエラーメッセージは、「単項演算子が必要です」または「二項演算子が必要です」です。

これは、上の表を作成したスクリプトです。

#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal

dw=5    # description column width
w=6     # table column width

t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }

o=/dev/null

echo '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'
echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'
echo '-----+------------------------------------+------------------------------------'

while read -r d t
do
    printf '%-*s|' "$dw" "$d"

    case $d in
        unset) unset t  ;;
        space) t=' '    ;;
    esac

    [ $t ]        2>$o  && t || f
    [ "$t" ]            && t || f
    [ -n $t ]     2>$o  && t || f
    [ -n "$t" ]         && t || f
    [ -z $t ]     2>$o  && t || f
    [ -z "$t" ]         && t || f
    echo -n "|"
    [[ $t ]]            && t || f
    [[ "$t" ]]          && t || f
    [[ -n $t ]]         && t || f
    [[ -n "$t" ]]       && t || f
    [[ -z $t ]]         && t || f
    [[ -z "$t" ]]       && t || f
    echo

done <<'EOF'
unset
null
space
zero    0
digit   1
char    c
hyphn   -z
two     a b
part    a -a
Tstr    -n a
Fsym    -h .
T=      1 = 1
F=      1 = 2
T!=     1 != 2
F!=     1 != 1
Teq     1 -eq 1
Feq     1 -eq 2
Tne     1 -ne 2
Fne     1 -ne 1
EOF

1
ありがとう!「変数を単一のかっこで囲む(列2a)」IMOのスタイルを採用することにしました。-nはノイズを追加し、読みやすさを低下させるだけです。同様に、長さがゼロまたは未設定のテストでは、[![-z "$ var"]の代わりに "$ var"]を使用します。
AllenHalsey 2010年

2
したがって、["vs [-n"(OPの最初の質問)のグラフは、完全に同等であることを示していますよね?
ホブ、2014

1
@hobs:はい。どちらを使用するかは、どちらがより明確であるかに依存します。また、Bashを使用する場合に推奨される二重ブラケット形式を使用する場合も、同等のものがあることに気付くでしょう。
追って通知があるまで一時停止。

1
だから、あなたの素晴らしいテーブルを要約するために、非ヌル文字列のテストに明確な(「より良い」)方法がある[["
コンロ

22

Bashに関する限り、より強力な [[ものを使用することをお勧めします。

通常のケース

if [[ $var ]]; then   # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string

上記の2つの構成要素は、見た目がすっきりとして読みやすくなっています。ほとんどの場合、それらで十分です。

単語の分割グロブの[[危険がないため、内部の変数展開を引用する必要がないことに注意してください。

およびに関するshellcheckのソフトな苦情を防ぐために、オプションを使用できます。[[ $var ]][[ ! $var ]]-n

まれなケース

「空の文字列に設定されている」と「まったく設定されていない」を区別しなければならないまれなケースでは、次のように使用できます。

if [[ ${var+x} ]]; then           # var is set but it could be empty
if [[ ! ${var+x} ]]; then         # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty

-vテストを使用することもできます。

if [[ -v var ]]; then             # var is set but it could be empty
if [[ ! -v var ]]; then           # var is not set
if [[ -v var && ! $var ]]; then   # var is set and is empty
if [[ -v var && -z $var ]]; then  # var is set and is empty

関連する投稿とドキュメント

このトピックに関連する投稿がたくさんあります。ここにいくつかあります:


9

ここにいくつかのテストがあります

文字列が空でなければ真:

[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"

文字列が空の場合は真:

[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"

これはOPのより良い方法は何かという質問には答えません。
codeforester 2018

0

正解は次のとおりです。

if [[ -n $var ]] ; then
  blah
fi

[[...]]変数の引用を正しく処理するの使用に注意してください。


2
-nBashで本当に必要ないときに使用するのはなぜですか?
codeforester 2018

0

空の環境変数を評価する代替の、おそらくより透過的な方法は、使用することです...

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi

10
これは、ボーンシェルデイズからの非常に古い学校です。この古い習慣を永続化しないでください。bash以前のバージョンよりもシャープなツールです。
tbc0

2
POSIX標準が廃止予定と明示的にマークする構文を回避している場合は、プリバッシュシェルではこれは必要ありません。POSIX準拠の実装[ "$ENV_VARIABLE" != "" ]すべてのシェルで動作しますtest -bashだけでなく、ash / dash / ksh / etcなど。
Charles Duffy、

...と言うことである、使用していない-a-o検査を組み合わせることではなく、使用し[ ... ] && [ ... ]たり[ ... ] || [ ... ]、テスト中に任意の変数のデータを使用して適用することができる唯一のコーナーケースが明確に閉鎖されています。
Charles Duffy、

-2

case/esacテストに使用:

case "$var" in
  "") echo "zero length";;
esac

12
いいえ、お願いします。これはcase意図されたものではありません。
tbc0

2
case3つ以上の選択肢がある場合に最適です。
codeforester 2018

caseこの種の使用は意図されていません。
Luis Lavaire、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.