エコー[[:digit:]]での予期しない動作


回答:


34

なぜなら、それらは2つの異なるものだからです。{1,2,3}一例であるブレース拡張{1,2,3}コンストラクトは拡張され、シェルによって前に、echoでもそれを見ています。あなたが使用すると何が起こるかを見ることができますset -x

$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3

ご覧のとおり、コマンドecho {1,2,3}は次のように展開されています。

echo 1 2 3

ただし、[[:digit:]]POSIX文字クラスです。に渡すとecho、シェルも最初に処理しますが、今回はシェルグロブとして処理されます。echo *現在のディレクトリ内のすべてのファイルを印刷する場合と同じように動作します。しかし[[:digit:]]、どの数字にも一致するシェルグロブです。bashでは、シェルグロブが何にも一致しない場合、それ自体に展開されます。

$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files

グロブが何かと一致する場合、それが出力されます:

$ echo /e*c
+ echo /etc
/etc

どちらの場合echoも、シェルが印刷するように指示したものをすべて印刷しますが、2番目の場合は、グロブが何か(/etc)と一致するため、その何かを印刷するように指示されます。

したがって、名前が正確に1桁([[:digit:]]一致するもの)で構成されるファイルまたはディレクトリがないため、グロブはそれ自体に展開され、次のようになります。

$ echo [[:digit:]]
[[:digit:]]

次に、というファイルを作成し5て、同じコマンドを実行してみます。

$ echo [[:digit:]]
5

そして、複数の一致するファイルがある場合:

$ touch 1 5       
$ echo [[:digit:]]
1 5

これは(このような)この動作をオフman bashにするnullglobオプションの説明に記載されています。

nullglob
    If  set,  bash allows patterns which match no files (see
    Pathname Expansion above) to expand to  a  null  string,
    rather than themselves.

このオプションを設定した場合:

$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]]  ## prints nothing

$ 

4
またはのshopt -s failglobような最新のシェルの動作と同様の、より有用な動作を得るためにも参照してください。zshfish
ステファンChazelas

私はステファンに同意し、を使用しますfailglobnullglob予期しない問題が発生する可能性があります。たとえば、たまたまが含まれているURLを貼り付ける場合など?です。
ケビン

1
確かに、私nullglobはパターンがシェルによってグロブとして解釈されていることを示すためだけに言及しました。
terdon

14

{1,2,3}あるブレース展開は、それはその意味を考慮せずにリストされた単語に展開されます。

[...]アスタリスクや疑問符と同様に、ファイル名の展開(またはワイルドカード、グロブ)で使用される文字グループです。これは、リストされている場合のように、名前付きグループのメンバーである文字、またはそれらにリストされている場合に一致します。ほとんどのシェルのデフォルトの動作では、一致するファイルがない場合、ワイルドカードをそのままにします。*?[:digit:]

(ワイルドカード/パターンをそれが一致する文字列のセットに実際に変換することはできないことに注意してください。アスタリスクは任意の長さの任意の文字列と一致できるため、それを含むパターンを展開すると文字列の無限リストが生成されます。)

そう:

$ bash -c 'echo [[:digit:]]'           # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]'            # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]'           # now there are two matches
1 3                                    # note that d, i, g and t do NOT match

それでも:

$ bash -c 'echo {1,2,3}'
1 2 3

それらの両方は、シェルによって展開され、それはあなたがしているが、実行中のコマンドがある場合は問題ではないls、またはechorm。また、これらのいずれかが引用されている場合、展開されないことに注意してください。

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}

Linuxの新機能です。エコーがファイルにどのように関連しているかをお聞かせください1 3。これは、私の引数としてstdoutに引数を出力して、ファイルを検索しないことです
AbdAllah Talaat

1
@AbdAllahTalaatこれは実際にはエコーとは関係ありません。シェル(例えばbashは)「拡大」になる[[:digit:]] にそれを渡していないechoので、echo決して見て[[:digit:]]、それだけで見ています1 3。あなたは実行することにより、この動作を確認することができますset -x(実行、実行されている実際のコマンドを出力しますどのset +x再びそれをオフにします)。
terdon

@AbdAllahTalaatは、シェルを実行する前にechoファイルを検索しません。echo
ilkkachu 2018年

特に、DOS / Windowsでは、ユーティリティはシェルではなくワイルドカードを展開すると思います。(私は多分間違っている)
ilkkachu 2018年

申し訳ありませんが、私は正しい答えをテドロンの答えにシフトしました。彼のコメントには、bashが動作をエコーし​​ないという意味が含まれていたためです...すべての回答とコメントに対する正解
AbdAllah Talaat

4

{1,2,3}(たとえば{1..3}、中かっこ展開です。これらは、コマンド実行前にシェルによって解釈されます。

[[:digit:]]パターンマッチングトークンですが、そのパターンに一致するファイルがある場所では使用していません。一致しないパターンマッチを使用すると、それ自体に展開されます。

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

いいえ、他の回答が正しく示しているように、パターンはファイル名と照合されます。
Toby Speight 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.