引用符を使用または使用せずに変数を定義することの違いは何ですか? [コピー]

引用符を使用または使用せずに変数を定義することの違いは何ですか? [コピー]

引用符で変数を定義する場合:

TEMP="~/Dropbox"

それから

ls $TEMP

動作しません。代わりに

echo $TEMP | ls

働く

同じ結果を得るには、引用符なしで変数を定義することもできます。

TEMP=~/Dropbox

これにより、簡単に入力できます。

ls $TEMP

私はそれらの違いについて混乱し、いつどこでこれら2つの定義をそれぞれ使用する必要があるかを知りたいと思います。

答え1

TEMP="~/Dropbox"

上記は、リテラルチルダとスラッシュを含む変数を定義します。引用符で囲まれているため、シェルは~/ホームディレクトリに展開されません。観察する:

$ echo "quotes=~/" noquotes=~/
quotes=~/ noquotes=/home/john1024/

~/したがって、ホームディレクトリを表すには~/引用符を外す必要があります。以下はうまくいきます:

TEMP=~/"Dropbox"

~/引用符で囲むとどうなるか考えてみましょう。

TEMP="~/Dropbox"
ls $TEMP

~/Dropbox上記のコマンドは、名前付きディレクトリにあるファイルを表すファイルを探します。名前付きディレクトリが存在しない可能性が高いため、「該当するファイルやディレクトリはありません」というエラーメッセージが返されます。Dropbox~~ls

また、以下のコマンドは思ったように機能しません。

echo $TEMP | ls

ls標準入力は無視されます。 barelsコマンドは、そのディレクトリが何であれ、現在のディレクトリのファイルのみを一覧表示します。

答え2

man bashして「チルダ拡張」を見つけます。

つまり、引用符のないチルダ(〜)はユーザーの家に置き換えられ、変数の一部である場合はもう発生しません。

$ T=~/Downloads
$ echo $T
/home/zstegi/Downloads

$ T="~/Downloads"
$ echo $T
~/Downloads

答え3

この問題にはいくつかの側面があります。まず、引用された代入文の効果は、次の2つの理由で引用符がない同じ代入文とは異なる場合があります。

  1. 課題に区切り文字が含まれている場合通事論トークン(例:;<>またはスペース)その後、引用符で囲むことができ、引用符のない割り当てステートメントはマーカーで区切られます。

    • 他のシェルでは、bashトークンは配列の割り当てを表す()ために使用される特別なケースですが、配列var=(...)拡張をサポートしていないPOSIXシェルでは、同じ構成は引用符なしで構文エラーになります。

      (   spc=  sc=; echo "<$spc>:<$sc>"
          spc=' ' sc=\;; echo "<$spc>:<$sc>"
      )
      

      <>:<>
      < >:<;>
      
  2. 割り当てに拡張マークが含まれていると、引用符によって拡張が発生しない可能性があり、拡張マークがないと拡張が発生する可能性があります。

    • 含まれるすべてのトークン以内に拡張は実際には拡張から割り当てられた変数に渡されるため、拡張は適用されません。
    • 二重引用符は式のシェル拡張"には使用できないため、通常は代入文では不適切です。ただし、次を含む式の拡張$には使用できます。$そしてコンテキスト内の他のシェルタグへの参照です。

      (   spc=\  sc=";" 
          tkns=$(printf "(<\n\'\t)>|")$spc$sc\"
          names=tkns$spc$"sc$spc$"spc
          printf ::$%s::\\n "$names" "$tkns"
      )
      

      ::$tkns $sc $spc::
      ::$(<
      \'  )>| ;"::
      

シェルトークンはシェルで非常に特殊な文字です。これは、コマンドを区別し、コマンドワードからコマンド引数まで区切る文字です。シェル語を分離/結合する文字です。シェルタグはシェル文字です。通事論パーサー(または語彙アナライザ)シェルは、コマンドのいくつかの拡張を考慮する機会がある前に、コマンドを読みながらそのアクションを見つけて実行します。

しかし、他のキャラクターもいます。ほぼ殻に特別です。これは、シェルパラメータ値に含まれる文字などのシェル拡張に影響を与える文字だけ$IFSでなく、?[*質問で述べたように~チルダなどのファイル名拡張メタ文字です。

特殊な場合、チルダを除いて、~これらの文字は代入文とは関係ありません。仕事コンテキスト(大リストコンテキスト)$IFS分割とファイル名拡張子の影響を受けません。したがって、変数の割り当てで発生する拡張には、コマンドのリストと同様にリテラル値の保護は必要ありません。

だから、次は動作します...

(meta=*?; meta=[$meta; echo "$meta")

[*?

しかし、チルダは~特別なシェル拡張です。拡張処理はalias、内容が常に文字通り拡張されるという点で非常にシェルに似ています。~チルダと拡張の両方 - 拡張を表すalias一般的なドル記号と同じです。$仕事状況 - はいいつもファイル名拡張子の影響を受けません$IFS。ただし、~チルダはほとんど常に引数に拡張され、値が<space>で終わる他の拡張シェルの直後aliasにない限り、シェルはそのコンテキストで拡張できないという点で異なります。alias

チルダ拡張は~どのような引用符でも発生せず、すべての点で適切に区切られていない場合、または末尾のコンテキスト名がシステムユーザーとシェルでこの事実を正しく認識できない限り、まったく発生しません。

だから...

~some_user

...ユーザーのホームディレクトリに展開されます。some_userシェルがそのようなユーザーが存在することを確認できれば、そうでなければまったく拡張されません。

到着正しく定義チルダ拡張の場合、右側の~引用符とaを除いて、すでに述べたシェルタグの1つを使用できます。/リスト文脈では、または仕事コンテキストは、/:または左、割り当て=ステートメントの最初または:他のどこにでもあります。

末尾のコンテキストがなく、~チルダが適切に区切られている場合、~チルダはシェル変数の現在の値に展開されます$HOME。これらの区別は、チルダ拡張について議論するときに誤って無視されます~。シェル変数は他の時間と同様にいつでも再割り当てまたは再割り当てできるため、ユーザーのホームディレクトリと値が$HOME同じである必要はありません。実際にいつ$HOMEunset$HOME はい unset~、POSIXは別々のチルダ拡張動作を維持します。指定されていないしかし、bash例えば、システム内の現在のユーザのホームディレクトリを見つける試みがなされる。

たとえば、

HOME="

:~"::~//~ bash -c '
    printf "\t<%s>" ~/ ~mikeserv/
    HOME=; echo
    printf "\t<%s>" ~/ ~mikeserv/
    unset HOME; echo
    printf "\t<%s>" ~/ ~mikeserv/
'

    <

:~::/home/mikeserv//~/> </home/mikeserv/>
    </> </home/mikeserv/>
    </home/mikeserv/>   </home/mikeserv/>

関連情報