グローバル拡張のために引用されていない変数のバックスラッシュ

グローバル拡張のために引用されていない変数のバックスラッシュ

次の6つのファイルが提供されます。

$ touch  'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'

なぜグローバル拡張のために引用されていない変数のバックスラッシュファイルのみ一致しますかsec\*et

$ v="sec\*et" ; ls $v
'sec\*et'
$ v='sec\*et' ; ls $v
'sec\*et'

これに関連してだから答えは、これPOSIXの定義:

<バックスラッシュ>はエスケープ文字という特別な意味を維持しなければなりません。後に次の文字のいずれかが続く場合にのみ特別と見なされます。

$ ` " \ <newline>

そしてバッシュマニュアル:

$バックスラッシュは、''、' `'、' "'、' \'、または改行文字のいずれかが後に続く場合にのみ特別な意味を維持します。二重引用符内では、これらの文字の1つに続くバックスラッシュが削除されます。特別な意味を持たない先行バックスラッシュ文字は変更されません。

変数のバックスラッシュ(アスタリスクの前)がリテラルバックスラッシュであることを知っています。

$ v='sec\*et' ; printf '%s' "$v" | hexdump -C
00000000  73 65 63 5c 2a 65 74                              |sec\*et|
00000007

*しかし、リテラルバックスラッシュ以降、ワイルドカードがなぜ特別な意味を失うのか理解できません。


私が理解する3つのこと:

*(A) 引用しない変数のアスタリスクは、グローバル拡張で特別な意味を持ちます。彼らは同じです:

$ v='sec*et' ; ls $v
'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'
$ ls sec*et
'sec*et'  'sec\*et'  'sec\et'   secet   secret  'sec\ xxx et'

*(B)バックスラッシュの後、アスタリスクは特別な意味を失います。

$ ls sec\*et
'sec*et'

(C)リテラルバックスラッシュのため、アスタリスクは*特別な意味を失うことはできません。

$ v='sec\\*et' ; ls $v
'sec\*et'  'sec\et'  'sec\ xxx et'
$ ls sec\\*et
'sec\*et'  'sec\et'  'sec\ xxx et'

私が理解していないものは次のとおりです。

ところで変な点は、アスタリスクは特別な意味を失いますが、バックスラッシュは削除されません。、この場合:

$ v='sec\*et' ; ls $v
'sec\*et'

どうやって見ると、文字通りのバックスラッシュの後に文字通りのアスタリスクが来るのと同じです。

$ ls sec\\\*et
'sec\*et'

しかし、なぜ?考慮する:

  1. 引用符内の特殊文字がリテラルになると(A)は保持されません。

  2. アスタリスクの後にバックスラッシュが続くのでリテラルになる場合sec*et(B)のようにバックスラッシュを削除し、fileと一致しないのはなぜですか?


アプリケーションでBracket Expressionを使用することに加えて、[*]glob拡張に使用されるときにリテラルアスタリスクと一致する文字列変数をどのように定義できますか?

$ v='sec < what what what > et' ; ls $v
'sec*et'

ベストアンサー1

$ v="sec\*et"
$ v='sec\*et'

どちらも変数をに設定しsec\*et、変数が値を取得する方法はワイルドカードの動作には影響しません。

sec\*etBashが引用しない後続の拡張を処理する方法は、エスケープされていないglob文字がないため、文字列がglobとして扱われないようです。別の言葉。たとえば、トリガーされず、failglobバックスラッシュは削除されません。代わりに、現状のまま印刷します。 (これはそれ自体がパターン一致ではありません。その名前のファイルがなくても文字列を返します。)

sec[*]etこれは以下に関連しています。はいボール。

また、それを使用するとsec\*et*globとなり、次に始まるファイル名と一致しますsec*et(つまり、バックスラッシュを削除)。

私が知っている限り、ほとんどのBashバージョンはこのように動作します。例外は Bash 5.0 です。これはsec\*etglobとして扱われ、例えばFailglobをトリガーします。

$ ./bash-4.4/bash    -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

$ ./bash-5.0/bash    -c 'shopt -s failglob; v="sec\*et"; echo $v'
./bash-5.0/bash: no match: sec\*et

$ ./bash-5.1.16/bash -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

$ ./bash-5.2.15/bash -c 'shopt -s failglob; v="sec\*et"; echo $v'
sec\*et

(すべてのケースですべてのシェルバージョンをテストしたわけではありません。)

おすすめ記事