状況 :
$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat ‘foo/*’: No such file or directory)
隠しフォルダとファイルがいっぱいのディレクトリがあります。何が起こっており、解決策は何ですか?
免責事項:この回答は特にBashを扱っていますが、その多くはグロブパターンに関する質問に適用されます!
スター文字(*
)はワイルドカードです。それに代わる特定の文字セットがあり、ドットである最初の文字(.
)はそれらの1つではありません。これは、Unixファイルシステムがどのように機能するかという特殊なケースであり、ドットで始まるファイルは「非表示」と見なされます。つまり、cp
、ls
などのツールは、明示的に指示されない限り、それらを「表示」しません。
まず、サンプルデータをいくつか作成しましょう。
$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}
したがって、次のようになります。
$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
`-- regfile3
それでは、ゲームをしてみましょう。コマンドecho
を使用して、特定のワイルドカード(*
)が次のような特定のコマンドに対してどのようになるかを一覧表示できます。
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3
$ echo reg*
regdir1 regdir2 regfile1 regfile2 regfile3
$ echo .*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2
$ echo .* *
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
$ echo .dotdir*
.dotdir1 .dotdir2
コマンドshopt -s dotglob
を使用して*
の動作を変更すると、regfile1
などのファイルに加えて、.dotfile1
にも一致するようになります。
bash
manページからの抜粋
dotglob If set, bash includes filenames beginning with a `.' in the results
of pathname expansion.
例:
$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
次のコマンドでこの動作を元に戻すことができます:
$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3
あなたは、パターン*
に一致するすべてのファイルをコピーすることをcp
に伝えていますが、ファイルはありません。
$ cp foo/.* .
または、foo
フォルダ内のすべてが必要な場合は、次のようにできます。
$ cp foo .
または、明示的にすることもできます。
$ cp foot/.* foo/* .
bash
でブレース展開を使用したよりコンパクトなフォーム:
$ cp foo/{.,}* .
いつでもecho
トリックを使用して、提案されたファイルパターンを確認できます(これは、星が含まれているものの空想的な用語です)。
$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3
ちなみに、ファイルのディレクトリと他のディレクトリをコピーする場合は、通常、これを再帰的に行います。これは、-R
からcp
への切り替えです。
$ cp -R foo/. .
zsh
を使用する場合の一般的な方法は、D
glob qualifier を使用することです([D] otファイルを含める):
cp foo/*(D) .
D
の有無にかかわらず、zshグロブには.
も..
も含まれないことにご注意ください(ご想像のとおり)。
シェルは*
文字を解決するときにこれらのファイルを非表示として処理しているため、cp
はこれらのファイル名を引数として受け取りません。
cp foo/.* .
を明示的に指定することで、それらをコピーできます。
すべてのファイルとディレクトリをある場所から別の場所にコピーしたい場合は、標準のrsync
コマンドを使用できます。上記の例では:
mkdir foo && touch foo/.test
rsync -a foo/ .
隠しファイルや隠しディレクトリを含むfoo
のすべての内容を再帰的に現在のディレクトリにコピーします。 foo/
の末尾のスラッシュは、rsyncにとって重要です。これを使用すると、foo
の内容のみがコピーされます。それがない場合、rsyncはfoo
もコピーします。例えば:-
mkdir src && mkdir dest && touch src/.test
rsync -a src dest // copies 'src' contents to 'dest/src'
rsync -a src/ dest // copies 'src' contents to 'dest'
マシン間のコピーを含む、Tweak rsyncには他にも多くのオプションがあります。
StéphaneChazelasのzsh answer は、グロブが含まれている単一の式では正しいです。ただし、デフォルトですべての式に設定する場合は、
setopt GLOB_DOTS
~/.zshrc
永続化します。