Bashの拡張ワイルドカードを使用して、ドットで始まるファイル名を無効にします。

Bashの拡張ワイルドカードを使用して、ドットで始まるファイル名を無効にします。

次のファイルがあるとしましょう。

xb@dnxb:/tmp/aaa/webview$ tree -F -C -a .
.
├── .git/
├── ss/
├── y
└── !yes/

3 directories, 1 file
xb@dnxb:/tmp/aaa/webview$ 

次のエスケープを使用すると、否定が正しく機能します!yes!\

xb@dnxb:/tmp/aaa/webview$ mkdir /tmp/aaa/webview2; cp -r -a !(\!yes) /tmp/aaa/webview2                                         
xb@dnxb:/tmp/aaa/webview$ l /tmp/aaa/webview2
total 16K
39331773 -rw-rw-r-- 1 xiaobai xiaobai ?    0 Jul  27 05:07 y
39331771 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 .git/
39331772 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 ss/
39331757 drwxrwxr-x 4 xiaobai xiaobai ? 4.0K Jul  27 05:44 ../
39331770 drwxrwxr-x 4 xiaobai xiaobai ? 4.0K Jul  27 05:44 ./
xb@dnxb:/tmp/aaa/webview$

しかし、!(.git)うまくいきません:

xb@dnxb:/tmp/test/hello$ rm -r /tmp/test; shopt -s extglob; shopt -s dotglob; mkdir -p /tmp/test/hello; mkdir /tmp/test/hello2; cd /tmp/test/hello; mkdir '.git'; cp -r -a !(.git) /tmp/test/hello2/; ls -la /tmp/test/hello2/
cp: will not create hard link '/tmp/test/hello2/hello' to directory '/tmp/test/hello2/.'
cp: cannot copy a directory, '..', into itself, '/tmp/test/hello2/'
total 16
drwxrwxr-x 4 xiaobai xiaobai 4096 Jul  27 16:05 .
drwxrwxr-x 4 xiaobai xiaobai 4096 Jul  27 16:05 ..
drwxrwxr-x 2 xiaobai xiaobai 4096 Jul  27 16:05 .git
drwxrwxr-x 2 xiaobai xiaobai 4096 Jul  27 16:05 hello2
xb@dnxb:/tmp/test/hello$ 

.働かないときの脱出\

xb@dnxb:/tmp/aaa/webview$ rm -r /tmp/aaa/webview2
xb@dnxb:/tmp/aaa/webview$ mkdir /tmp/aaa/webview2; cp -r -a !(\.git) /tmp/aaa/webview2        
cp: will not create hard link '/tmp/aaa/webview2/webview' to directory '/tmp/aaa/webview2/.'
cp: cannot copy a directory, '..', into itself, '/tmp/aaa/webview2'
xb@dnxb:/tmp/aaa/webview$ l /tmp/aaa/webview2                                         
total 24K
39331773 -rw-rw-r-- 1 xiaobai xiaobai ?    0 Jul  27 05:07 y
39331774 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:39 !yes/
39331775 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:39 webview2/
39331771 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 .git/
39331772 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 ss/
39331757 drwxrwxr-x 4 xiaobai xiaobai ? 4.0K Jul  27 05:44 ../
39331770 drwxrwxr-x 6 xiaobai xiaobai ? 4.0K Jul  27 05:44 ./
xb@dnxb:/tmp/aaa/webview$

デュアルスラッシュ\\も機能しません。

xb@dnxb:/tmp/aaa/webview$ rm -r /tmp/aaa/webview2
xb@dnxb:/tmp/aaa/webview$ mkdir /tmp/aaa/webview2; cp -r -a !(\\.git) /tmp/aaa/webview2
xb@dnxb:/tmp/aaa/webview$ l /tmp/aaa/webview2
total 20K
39331773 -rw-rw-r-- 1 xiaobai xiaobai ?    0 Jul  27 05:07 y
39331774 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:39 !yes/
39331771 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 .git/
39331772 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 ss/
39331757 drwxrwxr-x 4 xiaobai xiaobai ? 4.0K Jul  27 05:44 ../
39331770 drwxrwxr-x 5 xiaobai xiaobai ? 4.0K Jul  27 05:44 ./
xb@dnxb:/tmp/aaa/webview$ 

私はこれがうまくいくことがわかりました。

xb@dnxb:/tmp/aaa/webview$ rm -r /tmp/aaa/webview2
xb@dnxb:/tmp/aaa/webview$ mkdir /tmp/aaa/webview2; cp -r -a !(.git|.|..) /tmp/aaa/webview2
xb@dnxb:/tmp/aaa/webview$ l /tmp/aaa/webview2
total 16K
39331772 -rw-rw-r-- 1 xiaobai xiaobai ?    0 Jul  27 05:07 y
39331773 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:39 !yes/
39331771 drwxrwxr-x 2 xiaobai xiaobai ? 4.0K Jul  27 05:43 ss/
39331757 drwxrwxr-x 4 xiaobai xiaobai ? 4.0K Jul  27 05:45 ../
39331770 drwxrwxr-x 4 xiaobai xiaobai ? 4.0K Jul  27 05:45 ./
xb@dnxb:/tmp/aaa/webview$

なぜポイントを脱出するのは直接機能しないのですか?この場合、否定する正しい方法は何ですか? (!(.git|.|..)場合によっては予期しない結果が出る可能性があります。)

rsync除外するために使用できることを知っていますが、それは私の問題ではありません。

【書き直す】

テストケースに対してextglobとdotglobを有効にしましたが、原因ではありません。

失敗の原因は、拡張失敗によるものではなく、!(.git)エラー...中断によるものだと思います。.gitそして!(.git|.|..)それはすでに正しいアプローチでなければなりません。

ベストアンサー1

では、bashこのオプションがないと、dotglobglob以外の隠しファイルは無視されます。明らかに(つまり、文字通りの先導.)にはそれらが必要です。無視されませ.ん(..より合理的なシェルが望むものとはpdksh対照的にzshfish

globがで始まらない限り、dotglobsumだけは.無視されます。...

extglobを使用して、一部の拡張グローバル演算子のサポートがbash追加されました。kshただし、ここにはバグ/バグ機能があります!(...)

ksh(ではありませんがpdksh)およびbashでは、点@(.*)ファイルが明示的に要求されることがあります(文書ではこれについて明示的に言及しませんが)。

ただし、!(.git)ファイルをクリックするように求められません。シミュレーションは正しく処理しkshますが、ドットファイルを要求するとします。にも含まれます。したがって、コピーの一部としてコピーされます。zshkshbash...dotglob.git.

この問題を解決するには、次の接続を使用するか!([.]git)(ここでは[.]明確ではありません)、以下を除いて明示的に接続できます。.dotglob...!(.git|.|..)

$ bash -O extglob -c 'echo !(.git)'
. .. foo .foo
$ bash -O extglob -O dotglob -c 'echo !(.git)'
. .. foo .foo
$ bash -O extglob -O dotglob -c 'echo !([.]git)'
foo .foo
$ bash -O extglob -c 'echo !(.git|.|..)'
foo .foo

後者の場合、他のシェルと同様に、ドットファイルをここに含めないように将来のバージョンで変更される可能性があるため、dotglobオプションを追加します。bash

zsh独自のスプレッド演算子を持つものを使用する場合(extendedglobBourne互換性を維持するためにこのオプションはデフォルトで有効になっていません。そのkshglobオプションでksh globもサポートしていますが、これはより厄介です)。

set -o extendedglob # (in my ~/.zshrc)
cp -a -- ^.git(D) target/

(ファイル名がで始まらないことを保証できないため、そうする必要があることを-a意味します。)-r---

^.gitzshkshと同じです!(.git)。このglobのみを含みます(D)(のドットファイルは含まれません)。...

おすすめ記事