変数が空であってもtest -nがtrueを返すのはなぜですか?私は何が間違っていましたか? [コピー]

変数が空であってもtest -nがtrueを返すのはなぜですか?私は何が間違っていましたか? [コピー]

test(1)マニュアルページによると:

       -n STRING
              the length of STRING is nonzero

だから私はこれがうまくいくと期待しました。

[ -n ${var} ] && echo "var is not empty"

このロジックを実際のケースで使用しましたが、スクリプトは次のようになります。

[...]
dne() {
    echo DEBUG: wc -c: $(echo -n $peopkg |wc -c)
    echo DEBUG: pdir: $pdir
    echo "Error: ${package}: doesn't exist in local repos"
    exit 1
}


# packages are listed as such: 
# p/pname/package-version-release-distrelease...
# pname is inconsistent, but it is guaranteed that the first word in package
# (all to lowercase) will match at least one pname.
# NOTE: package-[0-9]* matches package-32bit. *-32bit is a subpackage we want
# to match later, but not when it's not already in pcase.
# So that must be negated too

pfirst=${pcase%%-*}
for pdir in ${p}/${pfirst}*
do
    # check if the glob matched anything at all
    [ ${pdir} = "${p}/${pfirst}*" ] && dne

    peopkg=$(find ${pdir} \
        -name ${package}-[0-9]* \
        ! -name *.delta.eopkg \
        ! -name ${package}-32bit* |sort -rn |head -1)
    echo DEBUG: in-loop peopkg: $peopkg
    echo DEBUG: in-loop wc -c: $(echo -n $peopkg |wc -c)
    echo DEBUG: in-loop test -n: $(test -n $peopkg && echo true || echo false)
    #------------------------------------------------------------#
    # break on ANY match. There's supposed to be only one anyway #
    [ -n ${peopkg} ] && break # <--- [issue here]                #
    #------------------------------------------------------------#
done
[ -z ${peopkg} ] && dne
[...]

ここで重要なのは、実行すると次のメッセージが表示されることです。

DEBUG: in-loop peopkg:
DEBUG: in-loop wc -c: 0
DEBUG: in-loop test -n: true
DEBUG: wc -c: 0
DEBUG: pdir: a/alsa-firmware
Error: alsa-utils: doesn't exist in local repos

これは私には理解できません。DEBUG: pdir: a/alsa-firmwareループが常に最初の反復で終了することを示します。これは、globパターンa / alsa *が何かと一致し、peopkgの長さがゼロ以外の場合にのみ発生します。

PS:私はPOSIXの互換性を研究しています。

ベストアンサー1

var空の文字列が含まれている場合([ -n $var ]トークン化後$var)、単語に展開されます[。これは、単一のパラメータがnullでないことをテストする単一のパラメータバージョンです。文字列が空ではないため、テストはtrueです。-n]test-n

GNU のマニュアルページでは、引用した段落の後にこの内容が記載されています。

   -n STRING
          the length of STRING is nonzero

   STRING equivalent to -n STRING

もちろん、問題は引用が不足していることです。スペースやその他の特殊文字が原因でシェルスクリプトが停止するのはなぜですか?そしていつ二重引用符が必要ですか?

引用符がないと、空の文字列だけが破損するわけではありません。var複数の単語が含まれている場合でも問題が発生する可能性があります。

$ var='foo bar'; [ -n $var ]
bash: [: foo: binary operator expected

またはワイルドカード:

$ var='*'; [ -n $var ]
bash: [: file.txt: binary operator expected

おすすめ記事