だからbashでは、私がするとき
echo \*
*
*はエスケープされ、文字どおりに解釈されるため、これは正しいようです。
しかし、私はそれを理解できない
echo \\*
\*
最初のバックスラッシュは2番目のバックスラッシュをエスケープすると思ったので、2つのバックスラッシュ「\\」はリテラルで1つの「\」を与えます。そして*はその特別な意味を持って続いた。私は期待していました:
echo \\*
\file1 file2 file3
回答の概要:\は文字どおりに解釈されるため、echo \*
はecho a*
と同様に動作し、文字 "a"で始まるすべてのファイルを検索します。
フォローアップの質問、正確に印刷したい場合
\file1 file2 file3
どのコマンドを使用すればよいですか?例えば次のように私はスペースが欲しい
echo \\ *
\ file1 file2 file3
現在のディレクトリにバックスラッシュで始まる名前のファイルがない場合、これは予想される動作です。バッシュ は、既存のファイル名と一致するように*
を展開しますが、 :
パターンが既存のファイル名またはパス名と一致しない場合、パターン文字列は変更されません。
\
で始まるファイル名がなかったため、パターンはそのままで、echo
には引数\*
が指定されています。この振る舞いはしばしば混乱を招き、zsh
のような他のシェルにはそれがありません。あなた はshopt -o failglob
を使用してBashで変更できます。これにより、zsh
と同様にエラーが発生し、診断に役立ちます誤動作する代わりに問題。
*
および?
パターン文字は、Wordのどこにでも出現でき、前後の文字は文字どおり一致します。そのため、echo \\*
とecho \\ *
はこのような異なる出力を提供します。最初のコードは\
で始まるすべてのコードに一致し(失敗)、2番目のコードは\
を出力し、次にすべてのファイル名を出力します。 。
安全に必要な出力を取得する最も簡単な方法は、おそらく printf を使用することです。
printf '\\'; printf "%s " *
echo *
は、異常なファイル名に-
または\
が含まれている場合は安全ではありません。
これを試して:
_printf "\\%s" "$(echo *)"
_
説明:
printf
は、フォーマット引数と、フォーマット文字列に代入される0個以上の引数を取ります\\
_は、_echo \\
_と同じ意味です。%s
_は、次の引数を取り、それを結果に代入することを意味します"$(echo *)"
means:_echo *
_を実行し、結果をprintf
の単一の引数に入れます。 printf
の動作方法のため、単一の引数に入れる必要があります試してみてください...
set file*
printf %s\ "\\$@"
配列の先頭にバックスラッシュを追加します-最初の要素のみです。終わりでも同じことができます。あなたはそれらをすべて\\
バックスラッシュのような:
printf \\%s file*
...または...
set file*; IFS=\\; printf %s\\n "$*"
技術的にのみ、またはEdgeの場合に限り、質問の後半の他のすべての回答(「どのコマンドを使用する必要がありますか?」)は間違っていると思います。私はこれが他の答えの問題に対処すると信じています:
(set -- *; echo "\\$*")
(FWIW)すべての書き込みが単一のコマンドで行われている
(printf '\\'; printf "%s " *; echo
とは異なります)。
set *
は定位置パラメーター($1
、$2
、$3
など...)を現在のディレクトリ内のファイルの名前に設定します。 (dotglob
オプションが設定されているかどうかに基づいて、.
(ドット)で始まるファイル名が含まれるか含まれない。)set *
(ダッシュ)で始まるファイルがある場合、-
は失敗する可能性があります(*
リストの最初のファイルです)。 set -- *
がこれを処理します。 --
は、「これ以降はすべて引数であり、オプションではない」と言います。$*
は位置パラメータ($1 $2 $3 …
)のリストです。 \\
を指定すると、\
(問題のコマンド例)と同様に、echo \\ *
が行の先頭に出力されますが、展開の妨げにはなりません後続の$*
。$*
は、位置パラメータ($1 $2 $3 …
)のリストですパラメータは$IFS
の最初の文字で区切られています。 $IFS
の最初の文字がスペースではない可能性がある場合は、(set -- *; IFS=" "; echo "\\$*")
もう少し詳細なオプションが含まれます
(set -- *; printf "%s\n" "\\$*")
そして
(set -- *; printf "\\%s\n" "$*")
これらは、-e
オプションがなくても、echo
が引数文字列のバックスラッシュを解釈する可能性がある環境でより安全です。
繰り返しますが、IFS=" ";
の最初の文字がスペースではない可能性がある場合は、$IFS
を追加してください。
echo \*
を実行すると、*
が表示されます*はエスケープされ、文字どおりに解釈されるため、これは正しいようです。
はい、エスケープ\
(引用符)を使用すると、それ以外の特殊文字は通常の文字になるため、*
としてそのまま出力されます。
しかし、それを理解できないので、
echo \\*
を実行すると\*
が表示されます
(グロビングを介して)展開する「文字列」について考える必要があるため。文字列は\\*
です。これは、引用符で囲まれておらず、特殊文字(バックスラッシュ)があるためです最初のバックスラッシュは2番目を引用符で囲みますとなり、oneになります。バックスラッシュとそれに続くアスタリスク(\*
)。文字列:バックスラッシュ(\
)の後に何か(*
)が続くと、文字どおり一致する必要があります。つまり、バックスラッシュで始まり、さらに文字が続くファイル名です。 \a
、\one
、\file
などのファイルがない場合、\*
のグロビングは失敗します。つまり、次のようになりますnot「ファイルのリスト」。 bashの一部のオプション(failglobまたはnullglob)が設定されていない場合、文字列\*
が残り、そのまま出力されます。あなたは\*
を取り戻します。
私は期待していました:
$ echo \\*
\file1 file2 file3
上記で、なぜ\\*
が文字列\*
になるのか、つまりone stringであることが明らかになりました。次のように2つの文字列を連結することはできません。
$ a='\'
$ b='file1 file2 file3'
$ echo "$a$b"
/file1 file2 file3
つまり、連結するにはtwo文字列が必要です。 1つの文字列はリテラル\
の変数で、もう1つの文字列は現在のディレクトリにあるファイルのリスト文字列としてです。これを達成する1つの方法は次のとおりです。
$ set -- * # get the list of files as arguments.
$ echo '\'"$*" # or "\\$*". Convert arguments to an string $*
# and concatenate '\' to it.
\file1 file2 file3