明示的な空の文字列に展開するように変数を設定しますか?

明示的な空の文字列に展開するように変数を設定しますか?

次のシェルスクリプト(example)があります(単純化)。

#!/bin/sh
./somecommand -s ${DOMAIN_SUFFIX:=.example.com}

実行すると./example正しく実行されます./somecommand -s .example.com

実行するとDOMAIN_SUFFIX=.stackexchange.com ./example正しく実行されます./somecommand -s .stackexchange.com

DOMAIN_SUFFIXQ:(スクリプト内で)明示的な空の文字列として渡されるようにどのように設定しますか?

つまり、実行する必要があります./somecommand -s ''

これを試しましたが、実行DOMAIN_SUFFIX='' ./example./somecommand -s失敗しました。

答え1

シェルがすべての拡張を行い、空のフィールドで終わった後は、引用しない限り削除されます。変数を参照していないため、空の「」と判断された場合は、「somecommands」パラメーターのリストからその変数を削除する必要があります。それだけでなく、DOMAIN_SUFFIXにスペースやワイルドカードがある場合は、「somecommand」に驚くこともあります。

また、${DOMAIN_SUFFIX:=.example.com} は表示された結果に基づく誤差です。DOMAIN_SUFFIX='' ./exampleこれは、空のDOMAIN_SUFFIXがそれをデフォルト値に置き換えてから、いくつかのコマンドの引数リストに入れるからです。したがって、「null」は表示されません。${DOMAIN=.example.com}あなたが得た結果を説明します。

答え2

使用:

"${DOMAIN_SUFFIX=.example.com}"

${パラメータ=デフォルト}、${パラメータ:=デフォルト}

パラメータが設定されていない場合は、デフォルト値に設定されます。

どちらの形式もほぼ同じです。 : $parameter が宣言され、null の場合のみ効果があります。

http://www.tldp.org/LDP/abs/html/parameter-substitution.html

補間後にヌル値が削除されないようにするには、引用符が必要です""(コードにヌル値がないことを確認しました。@Gillesに感謝します)。

また、=(または)は設定されていない場合はDOMAIN_SUFFIXにデフォルト値を割り当てるため、その値のみを取得する必要がある場合はそれを:=使用できます。-

答え3

TL、博士:スペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?。ああ、これはもっと長かったです…いいね、本当のTL、DR:変数とコマンドの置き換えには常に二重引用符を入れてください。また、スクリプトの2番目の問題については、この回答の終わりを参照してください。

スクリプト内の変数を空の文字列に拡張することはできません。引用符なしの変数拡張は「expand+split+glob」プロセスを経ます。

  1. 文字列である変数の値を取得します。
  2. スペースで文字列を分割します(より一般的には変数値の文字からIFS)。これにより、文字列のリストが生成されます(元の文字列にスペースのみが含まれている場合は空になる可能性があります)。
  3. リストの各要素に1つ以上のワイルドカード文字が含まれていて、要素が*?\[1つ以上のファイルと一致するパターンである場合、その要素は一致するリストに置き換えられます。

$DOMAIN_SUFFIX空の文字列リストに展開できますが、空の文字列を含むリストには拡張できません。ファイル名は空の文字列ではないため、ワイルドカード一致フェーズでは空の要素を作成できません。分割ステップでは、IFS区切り文字が一連の空白であり、一連の空白を破棄するには空白以外の文字が1つ以上必要なため、デフォルト値に設定された空の要素を作成することはできません。空白以外の文字を含めるように変更すると、分割フェーズで空の要素が生成される可能性がありますが、IFSそれを変更するにはスクリプトの変更が必要で、IFSそうする理由はありません。

Expand+split+glob 演算子を使用するのではなく、スクリプトを変更し、単純な変数拡張を使用する必要があります。つまり、変数拡張の周りに二重引用符を入れてください。

また、 の値が空の場合${DOMAIN_SUFFIX:=.example.com}に に拡張されます。したがって、空の文字列を取得できません。 null値を保持し、設定されていない場合にのみ使用するには、に変更します。.example.comDOMAIN_SUFFIX.example.comDOMAIN_SUFFIX:==

#!/bin/sh
./somecommand -s "${DOMAIN_SUFFIX=.example.com}"

答え4

bash私はこれがあなたが探しているマニュアルの一部だと思います(POSIXは同様の表現は同じ効果を持ちます):

部分文字列拡張が実行されない場合は、以下に示すフォーム(例:-:)を使用してbash設定されていないか、空の引数をテストします。コロンを省略すると、設定されていないパラメータのみがテストされます。

未設定変数とnull値を持つ変数の違いは、未設定変数が存在しないことです。

だから、

#!/bin/bash

bash -c 'echo "$#"; printf "%s\n" "$@"' -- "${DOMAIN_SUFFIX=.example.com}"

設定しない場合はその値に設定され、null(空の文字列)の場合は設定されませんDOMAIN_SUFFIX.example.comDOMAIN_SUFFIX

ここで使用されているコマンドは、渡さbashれたコマンドライン引数の数とそれに続くすべての位置引数を1行に1つずつ印刷する新しいプロセスを生成します。

bash-4.4$ bash script
1
.example.com
bash-4.4$ DOMAIN_SUFFIX=.hello.world bash script
1
.hello.world
bash-4.4$ DOMAIN_SUFFIX= bash script
1

bash-4.4$

最後の例ではとDOMAIN_SUFFIX=同じですDOMAIN_SUFFIX=''

関連情報