*がドットファイルと一致するかどうかを制御するための、グロビングのbashの設定とは


12

私が最近何かのようなことをしたときに驚いたのは、のような mv ./* ../somedirectory ファイル.gitignoreが移動されていないことでした。

私はOS Xのzshでほとんどの作業を行っていますが、この驚きはCentOSのbashで私に噛み付きました。OS Xでbashを試してみたところ、同じ動作が見つかりました*。ドットファイルと一致しません。これは私には非常に望ましくないようですが、明らかにbashのデフォルトです。(私が覚えているすべての場合、これもzshのデフォルトである可能性がありますが、.zshrcで何年も前に変更していて、これまでとは異なる動作をしたことを忘れている可能性があります。)

期待どおりに動作するようにbashを構成するにはどうすればよいですか。*がすべてのファイルに一致し、ドットファイルを無視しないようにします。

これがまったく不明確な場合のために、それを再現する方法を次に示します

cd /tmp
mkdir {t,d}est
touch test/{.,}{1,2,3,4,5,6,7}
ls -hal test
mv test/* dest
ls -hal test     # notice dot files are still there
ls -hal dest     # notice only some files were mv'ed


はい、それらは関連しています。私が検索したときにそれは表示されませんでした(おそらく、その質問者がグロビングやドットファイルに言及していなかったためでしょう)、それは実際には別の質問です。彼はファイルの移動方法を尋ねていました。私はシェルの動作、特にbashの動作を変更する方法を尋ねていました。その質問が私に表示されたかどうかは尋ねなかったかもしれませんが(bash設定が含まれる非常に完全で完全な答えがあるため)、それはまだ別の質問であり、私の質問への回答を探している人が必ずしも見つけられるわけではありません彼の質問。
iconoclast

「私の質問への回答を探している人が必ずしも彼の質問を見つけるわけではない」というビジネス全体が、このように質問を重複してクローズする方法がある理由です。
Gilles「SO-邪悪なことをやめよう」

はい、しかしあなたは要点を逃しているようです、それはそれが別の質問であるということです。
iconoclast

回答:


14

バッシュ

すでにお気づきのように、bashは.名前の先頭のスラッシュと一致しません。ドットに関するマッチングを変更するには、dotglobオプションを設定する必要があります-man bash

dotglob設定されている場合、bashには「。」で始まるファイル名が含まれます。に
    パス名展開の結果。

bashで有効/設定するにはshopt、を使用します。例:

shopt -s dotglob


zshの場合は、dotglobオプションを使用することもできますが、setopt有効にするには使用する必要があります。例:

setopt dotglob

2
zsh場合、より良いオプションは、globごとにdotglobを有効にすることですmv test/*(D) /dest
StéphaneChazelas 16

7

私はこれをテストし、それが問題を解決します:

shopt -s dotglob

出力:

~/stackexchangeanswers/40662$ ls -hal dest
total 8.0K
drwxr-xr-x 2 jodiec jodiec 4.0K 2012-06-12 22:15 .
drwxr-xr-x 4 jodiec jodiec 4.0K 2012-06-12 22:15 ..
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 1
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .1
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 2
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .2
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 3
-rw-r--r-- 1 jodiec jodiec    0 2012-06-12 22:15 .3
...snipped....

申し訳ありませんが、Ulrichが最初に回答しました。
iconoclast

3
私たちは全員同じチームに属しています。大丈夫です。
ジョディC

6

*シェルによって展開されるグロブです。デフォルトでは、シェルは.、先頭.が文字どおりに入力されない限り、名前が(隠しファイルまたはドットファイルと呼ばれる)で始まるファイルを含みません。

*or [.]*または?*or *.*またはdir/*dotfilesは含まれません。

.*またはdir/.*意志。

だからあなたはできる:

mv -- * .* /dest/

しかし含む一部のシェルbash(ただしzshmkshやはfishの拡張があること)が設計ミスを持っている.*含ま.そして..あなたは(私はそれ設計ミスと呼んでいる含めるグロブをしたいし、一般的には決して)ここではしたくない特別なディレクトリエントリを、。

そのため、(ボーンのようなシェルで)時々人々が使用することがわかります:

mv -- * .[!.]* ..?* /dest/

これは3つのグロブで、最初のファイルは非表示でないファイルに一致し、2番目のファイル名はファイル名で始まり、.その後に以外の文字が続き.、3番目のファイル名はファイル名で始まり..、少なくとも1文字が続きます。

しかし、いくつかの現代のシェルはそれを回避するより良い方法があります

zsh

ではzsh(D)グロブ修飾子を使用して、グロブにドットファイルを含めるように指定できます。

mv -- *(D) /dest/

zshまた、パターンが一致しない場合、mvコマンドが実行されないというBourneシェルのその他の誤った機能も修正しました。

上記のように、それは.また..そのグロブを含むことも決してしないので、

mv -- * .* /dest/

安全になります。ただし、一致するファイルがない*か、一致するファイルがない場合.*、コマンドは中止されるため、次のように使用することをお勧めします。

mv -- (*|.*) /dest/

他のいくつかのシェルと同様に、すべてのグロブにドットファイルを含めるように強制することもできます(たとえば、ドットファイルをより頻繁に含めたい場合):

setopt dotglob

または:

set -o dotglob

その後、特定のグロブにドットファイルを含めないようにするには、次のように記述します。

echo *(^D)

または:

echo [^.]*

バッシュ

残念ながら、bashglob修飾子はありません。したがって、dotfileをグローバルに含めることができます。ではbash、構文は次のとおりです。

shopt -s dotglob

(そして[^.]*隠しファイルのないグロブに使用します)。

ではdotglobbash含まれていない...のような塊で*、まだのような塊のために行います.*

あなたが設定されている場合GLOBIGNORE、空でない何かに変数を、それが自動的に有効にdotglobオプションと除外は.して..から.*グロブではなくからdir/.*か、.*/fileもの(!)という安全策はかなり無駄ですので。できますGLOBIGNORE='*/.:*/..:./*:../*:*/./*:*/../*'が、*/.or ./*やのようなグロブが壊れ../*ます。

より良い仕事は周りに使用することです[.]*か、dir/[.]*または[.]*/file(でdotglob有効)を除き、ドットファイルを展開する...

fishグロブには、.も含まれません..。バージョンに応じて、一致しない場合はzsh(またはbash -o failglob)またはのいずれかと同様に機能しますbash -o nullglob

mv -- * .* /dest/

隠しファイルと非隠しファイルの両方がある場合に機能します。それ以外の場合、YMMVおよび一部のバージョンでは、mv -- /destファイルがまったくない場合に呼び出されることがあります。

ksh93

ksh93どちらにもグロブ修飾子はありません。以下を使用して、ドットファイルをグロブに含めることができます。

FIGNORE='@(.|..)'

反しbashさんGLOBIGNOREも適切に行われています、の問題修正.*を含む.とします..

ヤシュ

yashdot-globオプション(set -o dot-glob)がありますが、とは逆にbash、グロブ拡張(の場合でも*)が含まれ.ている..ため、ほとんど役に立ちません。

tcsh

set globdot

以下のような作品はbash、つまりは*除くドットファイルが含ま.とし..たが.*、まだ含ん...(あなたが使用できる[.]*以外に隠されたファイルを展開する...)。


4

bashで一致するドットファイルを印刷する最も簡単な方法は、無視...て次のとおりです。

$ GLOBIGNORE=/+/
$ printf '%s\n' *


テストする:

$ cd tmp; mkdir empty; cd empty; touch {,.}{a..h}
$ GLOBIGNORE=/+/
$  ls *
a  .a  b  .b  c  .c  d  .d  e  .e  f  .f  g  .g  h  .h

それは注目に値するの例外を除いて、ドットまたはないと、すべてのファイルを印刷.して..

あなたの例も正しく動作します:

$ cd /tmp; mkdir {t,d}est; touch test/{,.}{a..h}
$ mv test/* dest/
$ ls -a test
.  ..
$ ls -a test/*
ls: cannot access test/*: No such file or directory

重要なファイルが空です。
システムファイルは. ..まだ存在しますが、シェル拡張(*を使用)には含まれません。

そして、dest inationディレクトリにはすべてのファイルが含まれています。

$ cd dest
$ ls -a *
a  .a  b  .b  c  .c  d  .d  e  .e  f  .f  g  .g  h  .h

どうして?

設定GLOBIGNOREがこの持っているので、これは動作しますサイドの効果を:

  • 展開時にdotglob(shopt -s dotglob)を数学ドットファイルに設定します。
  • ファイル名. および..は、GLOBIGNOREが設定されていてnullでない場合は無視されます。

マニュアルの詳細:LESS=+'/The GLOBIGNORE' man bash

また、変数GLOBIGNOREを設定して、ファイル名が一致しない可能性がある名前を含める必要があります

$ GLOBIGNORE=/+/

*一致するファイルがないときにが取得されないようにする必要がある場合は、nullglobも設定すると役立つ場合があります*


0

GLOBIGNORE = / + / @ user79743のこの設定に非常に興味があります

私の経験から未設定 dotglobがある悪いビジネスのほぼすべてのコマンド(cpは、MVなど)が、同じが本当であるに設定 nullglob(特に、その後脱出する必要は正規表現をを!)。

それでも、プログラムの最初にそれらを設定する必要があるが、cp、mvなどのコマンドを呼び出す、または正規表現を使用する特定の部分に干渉する場合は、次のようにします。

  # set dotglob, unset nullglob AFTER this
  is_nullglob=$( shopt -s | egrep -i '.*nullglob' )
  is_dotglob=$( shopt -s | egrep -i '.*dotglob' )
  [[ $is_nullglob ]] && shopt -u nullglob
  [[ ! $is_dotglob ]] && shopt -s dotglob
  # ... call commands ...
  # .....................
  # reset dotglob, nullglob to their previous values
  [[ $is_nullglob ]] && shopt -s nullglob
  [[ ! $is_dotglob ]] && shopt -u dotglob
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.