$ VAR vs $ {VAR}および引用するかしないか


139

私は書くことができます

VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"

私にとって最終結果はほぼ同じように思えます。なぜどちらかを書く必要があるのですか?ポータブル/ POSIXではないものはありますか?

回答:


99

VAR=$VAR1はの簡易版ですVAR=${VAR1}。2番目にできること、1番目にはできないことがあります。たとえば、配列インデックスを参照する(移植性がない)、またはサブストリングを削除する(POSIX移植可能)。POSIX仕様のBash Guide for Beginners and Parameter Expansionの変数詳細セクションを参照してください。

rm -- "$VAR1"またはのように変数を引用符で囲むことをrm -- "${VAR}"お勧めします。これにより、変数の内容がアトミック単位になります。変数値に空白(まあ、$IFS特殊変数の文字、デフォルトでは空白)またはグロビング文字が含まれていて、引用符で囲まない場合、各単語はファイル名生成(グロビング)のために考慮されます。やっています。

$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'

$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename

移植性について:POSIX.1-2008セクション2.6.2によると、中括弧はオプションです。


私はまた、移植性について興味ので、私の質問を更新し@shawn
xenoterracide

@shawn:あなたの例が正しいとは思えません。var1=$var拡張によりエラーが発生するシェルの実際の例はありますか?
アレックス

@alex:ありがとう。私はコマンドラインでそれをテストしたと思っていましたが、間違っていました。例を変更しました。
ショーンJ.ゴフ

更新された例では、引用されたバージョンが必要であることを念頭に置いておくとよいでしょう。例はかなり角質なケースだからです。
アレックス

9
@Shawn:割り当てには引用符は必要ありません。これらは、を含む他のほとんどの用途で必要export VAR=$VAR1です。中括弧については、オプションです(引用したセクションの4番目の段落を確認してください。これは、すべてのPOSIX以前およびPOSIXシェルの場合です)。
ジル

60

${VAR}$VARまったく同じです。単純な変数展開の場合、使用する唯一の理由${VAR}は、構文解析で変数名にあまりにも多くの文字を取り込む場合です${VAR1}_$VAR2(中括弧なしはに相当します${VAR1_}$VAR2)。ほとんどの飾られた拡張(${VAR:=default}${VAR#prefix}、...)は、中括弧が必要です。

変数の割り当てでは、フィールドの分割(値の空白での分割)とパス名の展開(つまりグロビング)がオフになるため、すべてのPOSIXシェルおよび聞いたすべてのPOSIX以前のsh VAR=$VAR1とまったく同じVAR="$VAR1"です。 。(POSIX ref:単純なコマンド)。同じ理由で、VAR=*確実VARにリテラル文字列に設定します*; が最初に別の単語であるため、もちろんVAR=a b設定VARされます。一般的に言えば、シェルの構文は、例えば、単一の単語を予測する場合、二重引用符は不要です(ではないパターンで)、それでもそこには注意する必要があります。たとえばPOSIXがあることを指定しますabcase … inリダイレクトターゲット>$filename)はスクリプト内で引用符を必要としませんが、bashを含むいくつかのシェルはスクリプト内でも二重引用符を必要とします。二重引用符が必要な場合を参照してくださいより徹底的な分析のため。

他の場合、特に多くのシェルで(export VAR="${VAR1}"同等に記述できるexport "VAR=${VAR1}")に二重引用符が必要です(POSIXはこの場合を開いたままにします)。このケースと単純な割り当ての類似性、および二重引用符を必要としないケースのリストの散在性により、分割とグロブを行わない限り、二重引用符を使用することをお勧めします。


2
一般的なルールとしてIFS、習慣にしたいので値に文字が含まれないことがわかっていても、変数展開を常に引用します。1つの例外は、変数の割り当て時に値を引用しないことです(値にスペースが含まれる場合など、必要な場合を除きます)。これにより、などのコマンド置換がある場合、エディター構文の強調表示がより便利になりますFOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}")。すべてを「文字列」の色で着色するのではなく、ネストされたコードの構文を強調表示します。これが、逆戻りを避ける理由でもあります。
リチャード・ハンセン

一方で>$filePOSIXスクリプトでOKですが、それは非対話(POSIX準拠のに強制されない限り場合でも、bashではありません$POSIXLY_CORRECT--posix...)。
ステファンシャゼル

で引用符が必要ないことは事実ですがVAR=$VAR1、に驚かされることがlocal VAR=$VAR1あります。いくつかの点で、少なくともいくつかのシェルでは、異なる方法で作業したことを覚えています。しかし、ATM、私は発散を再現することはできません。
dubiousjim

OK、私が覚えていた問題を見つけまし。一部のシェルでのみ表示されます。
dubiousjim

@dubiousjim local VAR=$VAR1はのようなものexport VAR=$VAR1で、シェルに依存します。
ジル

8

引用

二重引用符は変数の展開に使用され、単一引用符は強い引用、つまりsans拡張に使用されることを考慮してください。

拡張:

this='foo'
that='bar'
these="$this"
those='$that'

出力:

for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that

いくつかの理由で可能な限り引用を使用する必要があることに言及する価値があるかもしれませんが、その中で最も優れているのは、ベストプラクティスと読みやすさです。また、Bashは時々、一見非論理的または不合理/予期しない方法で風変わりであり、引用が暗黙的な期待を明示的に変更するため、エラーサーフェス(またはその潜在性)が減少します。

そして、引用しないこと完全に合法であり、ほとんどの場合に機能しますが、その機能は利便性のために提供されており、おそらく移植性が低くなります。意図と期待を反映することが保証されている完全に正式な慣行は引用することです。

置換

ここで、構造"${somevar}"が置換操作に使用されることも考慮してください。置換や配列など、いくつかのユースケース。

交換(ストリッピング):

thisfile='foobar.txt.bak'
foo="${thisfile%.*}"   # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}"  # removes longest matching

for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar

交換(交換):

foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}"   #single occurrence
bar="${foobar//least/most}"  #global occurrence (all)

for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful

配列:

mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls  
alpha=($(ls temp/*))

echo "$alpha"         #  temp/foo.txt
echo "${alpha}"       #  temp/foo.txt
echo "${alpha[@]}"    #  temp/bar.txt  temp/foobar.txt  temp/foo.txt
echo "${#alpha}"      #  12 # length of first element (implicit index [0])
echo "${#alpha[@]}"   #  3  # number of elements
echo "${alpha[1]}"    #  temp/foobar.txt # second element
echo "${#alpha[1])"   #  15 # length of second element

for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt

これはすべて、"${var}"置換コンストラクトの表面をかろうじて引っ掻いているだけ です。Bashシェルスクリプトの決定的なリファレンスは、libreオンラインリファレンス、TLDP The Linux Documentation Projectです。https://www.tldp.org/LDP/abs/html/parameter-substitution.html


1
非常に有益です。
オリオンelenzil

0
ls -la

lrwxrwxrwx.  1 root root      31 Nov 17 13:13 prodhostname
lrwxrwxrwx.  1 root root      33 Nov 17 13:13 testhostname
lrwxrwxrwx.  1 root root      32 Nov 17 13:13 justname

それから:

env=$1
    if [ ! -f /dirname/${env}hostname ]

カーリーを使用するより明確な例として言及する価値がある

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