変数が空であるか、スペースのみが含まれているかどうかをテストするにはどうすればよいですか?


240

次のbash構文は、param空でないかどうかを検証します。

 [[ !  -z  $param  ]]

例えば:

param=""
[[ !  -z  $param  ]] && echo "I am not zero"

出力なしとその罰金。

ときしかし、param1つ(またはそれ以上)のスペース文字を除いて空で、そして場合は異なります。

param=" " # one space
[[ !  -z  $param  ]] && echo "I am not zero"

「I am not zero」が出力されます。

スペース文字のみを含む変数を空と見なすようにテストを変更するにはどうすればよいですか?


4
からman test-z STRING - the length of STRING is zero。のすべてのスペースを削除する場合は$param、次を使用します${param// /}
dchirikov 14

6
WOW簡単でありませんtrim()内蔵の一切の* nixに機能しますか?非常に単純なことを実現するためのさまざまなハック
...-ADTC

6
@ADTC $(sed 's / ^ \ s + | \ s + $ // g' <<< $ string)は、私にとって十分に単純なようです。なぜ車輪を再発明するのですか?
jbowman

3
光沢がある可能性があるため
Inversus

1
それだけであることに注意し[[ ! -z $param ]]てくださいtest ! -z $param
ノアSussman

回答:


292

最初に、-zテストは明示的に次の目的で行われることに注意してください。

文字列の長さはゼロです

つまり、スペースのみを含む文字列は、長さがゼロではないため、の下でtrueになりません-z

必要なのは、パターン置換パラメーターの展開を使用して変数からスペースを削除することです。

[[ -z "${param// }" ]]

これにより、param変数が展開され、パターンのすべての一致(単一のスペース)が何も置き換えられないため、スペースのみを含む文字列は空の文字列に展開されます。


それがどのように動作するかの核心ザラザラはそれがある${var/pattern/string}の最初の最長一致置き換えるpatternとをstring。(上記のように)でpattern始まる場合、すべての一致を/置き換えます。置換は空なので、final /stringvalueを省略できます。

$ {parameter / pattern / string}

パターンは、単にファイル名展開の場合と同じようなパターンを生成するために拡張されます。パラメーターが展開され、パターンとその値の最長一致がstringに置き換えられます。場合はパターンが「/」で始まる、すべての一致パターンが置き換えられます文字列。通常、最初の一致のみが置き換えられます。... 文字列がnullの場合、パターンの一致は削除され、/次のパターンは省略できます。

その後、${param// }すべてのスペースを削除することになります。

なお、に存在するもののksh(それは元の場所)、zshおよびbashその構文はPOSIXではないとして使用すべきではない、shスクリプト。


sed彼らが言った...彼らが言っechoた変数を使用して
...-mikezter

1
うーん。もしそうであれば${var/pattern/string}、それはすべきではない[[ -z ${param/ /} ]]文字列であることを後のパターンとは何もするスラッシュの間のスペースに?
ジェシーチザム

@JesseChisholm "置換は空なので、最後の/と文字列値を省略できます"; 「文字列がnullの場合、パターンの一致は削除され、次のパターンは省略できます。」
マイケルホーマー

6
@MichaelHomer答えは[[ -z "${param// }" ]]確かにpattern空であり、replacement string単一のスペースのように見えます。ああ!私はif pattern begins with a slashその部分を見逃したようになりました。そのため、パターンは/ あり、文字列は省略されているため、空です。ありがとう。
ジェシーチザム

bash注:set -o nounset(set -u)で実行し、paramが設定されていない場合(nullまたはスペースで埋められているのではなく)、バインドされていない変数エラーが生成されます。(set + u; .....)このテストは免除されます。
ブライアンクリスマン

31

文字列が許可されたセットの文字のみを含むことを確認する簡単な方法は、許可されていない文字の存在をテストすることです。したがって、文字列にスペースのみが含まれているかどうかをテストする代わりに、文字列にスペース以外の文字が含まれているかどうかをテストします。bash、kshまたはzshの場合:

if [[ $param = *[!\ ]* ]]; then
  echo "\$param contains characters other than space"
else
  echo "\$param consists of spaces only"
fi

「スペースのみで構成される」には、空の(または未設定の)変数の場合が含まれます。

空白文字をテストすることもできます。[[ $param = *[^[:space:]]* ]]ロケール設定、またはテストする空白文字の明示的なリストを使用するために使用します。たとえば[[ $param = *[$' \t\n']* ]]、スペース、タブ、または改行をテストします。

文字列を=内側のパターンと照合すること[[ … ]]は、ksh拡張機能です(bashとzshにもあります)。Bourne / POSIXスタイルでは、caseコンストラクトを使用して文字列をパターンに一致させることができます。標準のシェルパターンは、ほとんどの正規表現構文のようにで!はなく、文字セットを無効にするために使用することに注意してください^

case "$param" in
  *[!\ ]*) echo "\$param contains characters other than space";;
  *) echo "\$param consists of spaces only";;
esac

空白文字をテストするために、$'…'構文はksh / bash / zshに固有です。これらの文字を文字通りスクリプトに挿入することができます(バックスラッシュ+改行が何も展開しないため、改行は引用符で囲む必要があることに注意してください)。

whitespace=$(printf '\n\t ')
case "$param" in
  *[!$whitespace]*) echo "\$param contains non-whitespace characters";;
  *) echo "\$param consists of whitespace only";;
esac

これはほとんど優れていますが、まだ、尋ねられた質問には答えていません。現在、未設定または空のシェル変数とスペースのみを含むシェル変数の違いがわかります。私が意味する-あなたが私の提案を受け入れる場合は、まだ明示的に設定されるためのシェル変数をテストし、他の回答でconveredないのparam拡張フォームに追加されます${var?not set}-そのテストに合格し、存続があなたにマッチする変数があることを確実にする*) case決定的に影響を与えるだろうたとえば、答えてください。
mikeserv 14

修正-これは、実際には、考えもともと尋ねた質問に答えるが、それ以来、それは根本的に質問の意味を変更し、したがって、あなたの答えを無効にするような方法で編集されています。
mikeserv 14

で必要[[ $param = *[!\ ]* ]]ですmksh
ステファンシャゼル14

20

POSIXly:

case $var in
  (*[![:blank:]]*) echo '$var contains non blank';;
  (*) echo '$var contains only blanks or is empty or unset'
esac

blanknon-blankemptyunsetを区別するには:

case ${var+x$var} in
  (x) echo empty;;
  ("") echo unset;;
  (x*[![:blank:]]*) echo non-blank;;
  (*) echo blank
esac

[:blank:]は、水平方向のスペース文字(ASCIIのスペースとタブですが、おそらくロケールにはさらにいくつかあります。一部のシステムには、改行なしスペース(使用可能な場合)が含まれますが、含まれないシステムもあります)。あなたにも(改行やフォームフィードなどの)垂直間隔の文字が必要な場合は、交換してください[:blank:][:space:]


POSIXlyは(おそらくより良い)ダッシュで動作するので理想的です。
ケンシャープ

zshに問題があるようです[![:blank:]]、それ:bは無効な修飾子です。ではshkshエミュレートし、それがイベントを発生させるが見つかりません[
cuonglm

@cuonglm、何をしようとしましたか?var=foo zsh -c 'case ${var+x$var} in (x*[![:blank:]]*) echo x; esac'私にとっては大丈夫です。検出されないイベントは、対話型のシェル専用です。
ステファンシャゼラス

@StéphaneChazelas:ああ、そうですね、インタラクティブなシェルで試しました。:b無効な修飾子は少し奇妙です。
クオングルム

1
@FranklinYuは、OS / Xの上にshされbashて構築された--enable-xpg-echo-default--enable-strict-posix-default(関係Unixの対応となるようにecho '\t'タブを出力します)。
ステファンシャゼル

4

優れたスクリプト言語のスクリプトではなく、シェルスクリプトを記述する唯一の理由は、極端な移植性が最優先事項である場合です。 レガシーは、/bin/shあなたが持っている確信できる唯一のことですが、例えばPerlはある以上バッシュより利用可能なクロスプラットフォームである可能性が高いです。したがって、真に普遍的ではない機能を使用するシェルスクリプトを作成しないでください。また、POSIX.1-2001より前に、いくつかの独自のUnixベンダーがシェル環境を凍結したことに留意してください。

このテストを実行するポータブルな方法がありますが、使用する必要がありますtr

[ "x`printf '%s' "$var" | tr -d "$IFS"`" = x ]

$IFS便利なデフォルト値は、スペース、タブ、および改行です。)

printfビルトイン自体は非常に移植性がありますが、どのバリアントechoを持っているかを把握するよりも、それに依存する方がはるかに簡単です。)


1
それは少し複雑です。文字列に特定の文字が含まれているかどうかをテストする通常の移植可能な方法はcaseです。
ジル14

@Gilles caseglob を記述して、空の文字列または空白文字のみを含む文字列を検出することはできません。(正規表現を使用すると簡単になりますが、正規表現をcase実行しません。改行を気にする場合、回答の構成は機能しません。)
zwol 14

1
私は答えの例としてスペースを与えました。それが質問が求めたものだからです。空白文字のテストも同様に簡単ですcase $param in *[![:space:]]*) …IFS文字をテストする場合は、パターンを使用できます*[$IFS]*
ジル14

1
@mikeserv 真剣に防御的なスクリプト<space><tab><newline>では、最初にIFSを明示的に設定し、それ以降は二度と触れません。私はそれが気晴らしだと思った。
zwol

1
パターンの変数に関しては、すべてのBourneバージョンとすべてのPOSIXシェルで機能すると思います。大文字と小文字のパターンを検出し、変数の展開をオフにするために余分なコードが必要になります。それを行う理由は考えられません。.profile多くのBourneシェルによって実行されたインスタンスがいくつかあります。もちろん、デフォルト以外の特定の値(空の(または設定解除された)を含む、またはで始まる)がある[$IFS]場合、意図したとおりには動作しません。IFS]!^
ジル14

4
if [[ -n "${variable_name/[ ]*\n/}" ]]
then
    #execute if the the variable is not empty and contains non space characters
else
    #execute if the variable is empty or contains only spaces
fi

これは、単一のスペースではなく、空白文字を取り除きますよね?おかげで
アレクサンダーミルズ

0

変数が空であるかスペースが含まれているかどうかをテストするには、次のコードも使用できます。

${name:?variable is empty}

2
「またはスペースを含む」が真実ではないので、あなたの答えは否定されていると思います。
ベルンハルト14

注意してください-現在のシェルを強制終了します。(:$ {subshel​​l?})に入れる方が良いでしょう。また、それはstderrに書き込みます-おそらくリダイレ​​クトが必要です。そして、最も重要なのは、変数の実際の値が未設定またはヌルでない場合に評価されることです。そこにコマンドがある場合、あなたはそれを実行しました。そのテストをで実行するのが最善:です。
mikeserv 14

シェルを殺す方法。uはまた、最初に定義し、これをテストすることができname=aaaa、このコマンドを実行しecho ${name:?variable is empty}、それが変数名の値を印刷して、今、このコマンドを実行するecho ${name1:?variable is empty}ことが印刷されますNAME1を:変数が空である-SH
pratik

はい- echo ${name:?variable is empty}に評価し、いずれか$nameの非null値を、それはシェルを殺すでしょう。したがって、同じ理由で、prompt > $randomvarどちらも実行しないでください${var?}-コマンドが存在する場合、おそらく実行されます-そして、それが何であるかわかりません。対話型シェルは終了する必要はありません-これがあなたの終了しない理由です。それでも、いくつかのテストを見たい場合は、ここに多くのテストがあります。この1はかなり限り...ではありません
mikeserv

0

変数が設定されていない、空であるか(null値がある)、またはスペースのみが含まれているかどうかをテストするには:

 [ -z "${param#"${param%%[! ]*}"}" ] && echo "empty"

説明:

  • の拡張は${param%%[! ]*}、最初の非スペースから最後まで削除します。
  • 先行スペースのみが残ります。
  • 次の展開では、変数から先頭のスペースが削除されます。
  • 結果が空の場合、変数は最初は空でした。
  • または、変数が空ではない場合、先頭のスペースを削除すると空になります。
  • 結果が空の場合、-zecho empty

上記はPOSIX互換であり、Bourneの子孫で実行されます。

それをタブにも拡張する場合は、明示的なタブを含めます。

 [ -z "${param#"${param%%[!     ]*}"}" ] && echo "empty"

または、削除する必要がある文字を含む変数を使用します。

 var=$' \t'   # in ksh, bash, zsh
 [ -z "${param#"${param%%[!$var]*}"}" ] && echo "empty"

または、POSIXの「文字クラス式」を使用できます(空白はスペースとタブを意味します)。

 [ -z "${param#"${param%%[![:blank:]]*}"}" ] && echo "empty"

しかし、mksh、lksh、およびposhでは失敗します。


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