_/home/user/project/.git
_などのファイル名に一致するパターンを作成する場合、_.
_文字を「明示的に」、つまり_shopt -s dotglob
_を使用せずにどのように一致させますか?
https://www.gnu.org/software/bash/manual/html_node/Filename-Expansion.html のマニュアルには次のように記載されています。
ファイル名の展開にパターンを使用する場合、シェルオプションdotglobが設定されていない限り、ファイル名の先頭またはスラッシュの直後の文字「。」を明示的に一致させる必要があります。
正確には、「明示的に一致する」とはどういう意味ですか?
また、 http://www.tldp.org/LDP/abs/html/globbingref.html (最後のNotes
セクション)でも、同じ概念が取り上げられています。 :
ファイル名の展開はドットファイルと一致できますが、パターンにリテラル文字としてドットが明示的に含まれている場合に限ります。
このメモには、次の例が示されています。
_~/[.]bashrc # Will not expand to ~/.bashrc
~/?bashrc # Neither will this.
# Wild cards and metacharacters will NOT
#+ expand to a dot in globbing.
~/.[b]ashrc # Will expand to ~/.bashrc
~/.ba?hrc # Likewise.
~/.bashr* # Likewise.
_
「ドットファイル」を含むように拡張される最後の3つの例の内部動作を理解できません。
具体的には、_.
_の後にb
を角かっこで囲むと、例_~/.[b]ashrc
_でこれが「明示的な」一致になりますか?以降の例は、私にはさらにあいまいです。 _.
_文字とはまったく関係がないように見える方法でパターンを操作すると、パターンがどのように一致するのか理解できません。
_shopt -s dotglob
_の使用を避けたい理由に関して、この質問のきっかけは、別のプログラムの構成ファイルで使用するためにこれらのパターンを作成しているという事実に根ざしています。たとえば、「非表示の_.git
_ディレクトリ」を含むパスを除外したいのですが、dotglob
を任意の容量で指定できるかどうかわかりません。
本質的に:「明示的であること」によって_.
_文字を一致させる最も簡単な手段は何ですか?次の文字を角かっこで囲むと「機能します」が、その理由を知りたいのですが。そのアプローチで「暗闇で撮影」しているような気がします。
この点に関する根本的な振る舞いに関する説明は大歓迎です。
追加する編集:
最初は関連性がないように見えましたが、人々は私のユースケースの詳細に興味を持っているようですので、さらに説明します。
Samhain
と呼ばれるホストベースの侵入検知ソフトウェアを使用しています。 Samhainは、特定のユーザー指定の構成パラメーターに従ってファイルシステムが変更されるたびに「アラート」を出します。
私は_.git
_ディレクトリ内のファイル(特定の親ディレクトリ内にある)が作成/変更/削除されたときにSamhainに警告させたくない。サムハインでは、このタイプの除外は「無視ルール」を定義することによって実行されます。これらのルールの正確な仕様は、_4.2. File/directory specification
_の http://www.la-samhna.de/samhain/manual/filedef.html で説明されています。
要するに:
Wildcard patterns ('*', '?', '[...]') as in Shell globbing are supported for paths. The leading '/' is mandatory.
そのため、問題の_.git
_ディレクトリに一致する「無視ルール」を作成しようとしています。これにより、Samhainは監視アクティビティからそれらを除外します。
最初に、私はこれを試しました:
_[IgnoreAll]
dir = -1/home/user/project/*/*/.git
_
これは機能しませんでした。それらの_.git
_ディレクトリ内のファイルが変更されるたびにSamhainは引き続き警告を発しました。
上で引用した例を見つけたら、私はこれを試しました:
_dir = -1/home/user/project/*/*/.[g]it
_
この変更により、Samhainは必要に応じてファイルを無視します。
この質問を投稿する際に、私は単にその変更が意図した効果をもたらす理由を理解しようとしていました。
私が最初に使用しようとしていたパターンそのものが、「エコー」テストを使用するときに問題の_.git
_ディレクトリと実際に一致することを考えると、私はそれほど愚かではないと言います。
_echo /home/user/project/*/*/.git
_
したがって、Bashでのパターンマッチング、グロブ、またはファイル名の拡張に関して、基本的なことを誤解していることはそれほど多くありませんでした。それどころか、特にサムハインがこの文脈でパターンマッチングをどのように実装するかに関しては微妙な違いがあるようです。
Samhainの構成ファイルのコンテキストで適用したときにこれが機能しない理由がわかりません(明らかに)。この編集があれば、誰かが説明できるかもしれません。
まず、パス名パターンで[b]
、?
、*
などが何を意味するかを知っていると思います。 (そうでない場合は、さらに調査を行ってください。)
他の人が言ったことを繰り返すリスクを冒して、あなたはそれを考えすぎています。文字列/.
を含むパターン(つまり、/
immediatelyの後に.
が続く)は、リテラルとしてドットを明示的に含みますキャラクター。重要なのは、[b]
、?
および/または*
が発生することです後.
影響しないパターンがドットファイルと一致できるかどうか。最後の3つの例は、~/.bashrc
に一致するpatterns(つまり、プレーンファイル/パス名だけでなく、複数のファイル/パス名に一致する可能性のあるもの、またはまったく一致しないもの)の例として提供されています。 —最初の2つとは対照的に、~/.bashrc
が特別に処理されなかった場合、would.
と一致します。
それで、あなたの本当の質問は何ですか?
…別のプログラムの構成ファイルで使用するために、これらのパターンを作成しています。たとえば、「非表示の
.git
ディレクトリ」を含むパスを除外したいのですが、dotglob
を任意の容量で指定できるかどうかわかりません。
すべてのファイル/ディレクトリに対して(chown
やcp
など)何かをしたいと思いますexceptドットで始まるもの。しかし、あなたのコードは他の誰かのスクリプトで(.
またはsource
コマンドを介して)使用されることになり、your_command *
を実行することを恐れています。スクリプトがdotglob
を設定している可能性があるため、*
は「非表示」ファイルを含むすべてのファイルに展開されます。また、既存のスクリプトの機能を壊したくないので、dotglob
をオフにしたくありません。
よりスマートなワイルドカード(パス名拡張パターン)を使用します。
[abc]
のようなワイルドカード(別名グロブ)を理解していただければ幸いです。ワイルドカードは、a
、b
、またはc
のいずれかの文字と一致します。たとえば、文字列c[aou]t
はcat
、cot
、およびcut
と一致します。 d[iou]g
はDig
、dog
、およびdug
と一致します。 (これらは範囲で使用でき、通常は使用されます。たとえば、[a-z]
および[0-9]
です。)まあ、これの特殊なケースは[!abc]
です—任意の文字に一致します例外a
、b
またはc
。したがって、[!.]*
(またはdirectory_name/[!.]*
)を使用して、ドット以外の文字で始まる名前を照合できます。逆説的ですが、dotglob
が設定されていない場合、[.]
(ファイル名の先頭)はドットと一致しませんが、[!.]
はexcludeドットとは関係ありませんdotglob
の設定の.
これにより、dotglob
が設定されているかどうかに関係なく同じ結果が得られます。
dotglob
(サブシェル内)を使用します。
シェルオプション(shopt
s)はプロセスに対してローカルであり、プロセス属性が子から親に逆方向(上り坂)に流れることはありません。そう
(shopt -u dotglob; your_command *)は、スクリプトの残りの部分の設定や動作に影響を与えることなく、隠しファイル以外のファイルでのみ実行されます
your_command
。dotglob
を使用します(サブシェルを使用せずに)。
余分なリソースを使用するため、サブシェルを避けることを好む人もいます。ただし、コストはごくわずかであるため(many回実行するループで実行しない限り)、これはあまり適切な理由ではありません。サブシェルを回避するより良い理由は、cd
やumask
などのシェルの環境に影響を与える何かをする必要がある場合です。
このような状況の場合は、一時的にdotglob
をオフにして、後で以前の設定に戻すことができます。
shopt dotglob
(-s
または-u
なし)と入力すると、dotglob
オプションの現在の設定が報告(表示)されます。 (shopt
with no parametersは、allオプションの現在の設定を一覧表示します。)また、それに応じて終了ステータスを設定します。 -q
フラグは表示を抑制するため、次のことができます。
shopt -q dotglob dotglob_setting = $? shopt -u dotglob your_command * if ["$ dotglob_setting" = 0] then shopt -s dotglob fi
しかし待ってください…「別のプログラムの構成ファイル」とおっしゃいました。あなたは何について話していますか? ignore=*.o
のようなファイルの作成または変更について話している場合、そのファイルはどのプログラムでも処理(および解釈)されるため、この質問全体は意味がありません。 そのプログラムは*
の解釈方法を決定します—シェルはそれとは何の関係もありません。
さて、質問が何であるかについてのより良い考えができたので:
簡単に言えば、あなたが見ている行動は意味をなさないということです。 .git
ディレクトリが存在する場合、それを.git
として正確に(文字通り)指定し、.[g]it
のワイルドカード/グロブパターンで指定すると同じように動作するはずです。
長い答え:私は私の答えの最初のバージョンの最後の段落を支持します。 Samhainは、ポリシー構成ファイルを読み取って解析しています。シェルを使用して構成ファイル内のワイルドカードを解釈する場合がありますが、内部で実行していると思います。
また、「シェルを使用している」場合、どのシェルを使用していますか?多くのシステムでは、/bin/sh
はbashではありません。パス名の展開パターン(ワイルドカードなど)に関するベースラインの動作は同じである必要がありますが、ポーチを降りると沼地になります。シェルのPOSIX仕様にはshopt
コマンドすらなく、(AFAIK)には*
をallファイルに展開する方法がありません(および非表示のものだけではありません)。
あなたが好きなら 無駄に これにもう少し時間をかけて、/home/user/project/*
をSamhain構成ファイルに入れて、それがすべてのファイルとして解釈されるのか、非表示でないファイルとして解釈されるのかを確認してみてください。それがすべてのファイルとして解釈される場合、私たちは結論を下すことができます
/bin/sh
を使用していません。*
はすべてのファイルを意味します。dotglob
モードでbashを使用してワイルドカードを展開しています。しかし、これは意味がありません。すでに述べたように、.git
と.[g]it
の処理は、私が知っているシェルの通常の動作に対応していません。ほぼ確実に、ワイルドカード用の独自のコードがあります。しかし、いずれにせよ、あなたの結論は正しいと自信を持って言えると思います。Samhainには、IgnoreAll
仕様でのワイルドカードの処理に関してバグがあります。ベンダーにバグレポートを提出することをお勧めします。または、回避策を見つけたので、それを忘れることができます。
ファイル名の展開にパターンを使用する場合、シェルオプションdotglobが設定されていない限り、ファイル名の先頭またはスラッシュの直後の文字「。」を明示的に一致させる必要があります。
これは単に、グロブ*
、?
、および[...]
がファイル名の先頭の.
と一致しないことを意味します。ファイル名の先頭にある.
と一致させたい場合は、globを使用できません。明示的に.
を入力する必要があります。例えば:
$ echo ????
Work
$ echo .???
.gem .pki .ssh .vim
そしてあなたの他の質問に答えるために:
具体的には、
.
の後にb
を角かっこで囲むと、例~/.[b]ashrc
でこれが「明示的な」一致になりますか?
グロブパターンを使用しているからといって、wholeパターンが「明示的」ではなくなったわけではありません。たとえば、~/.[b]ashrc
では、文字/.ashrc
はすべて明示的に一致します。ただし、[b]
はグロブパターンであり、明示的な一致でもありません。 (技術的には、~
はチルダ展開であり、glob展開よりも前に実行されるため、明示的に一致します。)ただし、.
、do一致を含む他の文字明示的に、これが~/.[b]ashrc
が~/.bashrc
と一致する理由です。
比較のために、~/?[b]ashrc
は明示的に一致しなくなったため、~/.bashrc
はnot.
と一致します。