cp ukryte pliki z wzorami glob

13

Sytuacja :

$ mkdir foo && touch foo/.test
$ cp foo/* .
zsh: no matches found: foo/*
(or bash : cp: cannot stat foo/*’: No such file or directory)

Mam katalog pełen ukrytych folderów i plików. Co się dzieje i jakie jest rozwiązanie?

Gradient
źródło
dotglobjest tłumaczone globdotsprzez zsh, który jest niepoprawną nazwą opcji dla bash .

Odpowiedzi:

19

Uwaga: Ta odpowiedź dotyczy Basha, ale w dużej mierze dotyczy pytania dotyczącego globalnych wzorców!

Znak gwiazdy ( *) to symbol wieloznaczny. Istnieje pewien zestaw znaków, który zajmie miejsce, a pierwszy znak będący kropką ( .) nie jest jednym z nich. Jest to szczególny przypadek tylko ze względu na to, jak działają systemy plików Uniksa, pliki zaczynające się od kropki są uważane za „ukryte”. Oznacza to, że narzędzia takie jak cp, lsitp nie „widzą” je, chyba że wyraźnie powiedziano, aby to zrobić.

Przykłady

Najpierw stwórzmy przykładowe dane.

$ mkdir .dotdir{1,2} regdir{1,2}
$ touch .dotfile{1,2} regfile{1..3}

Więc teraz mamy następujące:

$ tree -a
.
|-- .dotdir1
|-- .dotdir2
|-- .dotfile1
|-- .dotfile2
|-- regdir1
|-- regdir2
|-- regfile1
|-- regfile2
`-- regfile3

Teraz zagrajmy w kilka gier. Możesz użyć polecenia, echoaby wyświetlić listę konkretnych symboli wieloznacznych ( *) dla danego polecenia, takich jak:

$ 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

Zmieniasz zachowanie?

Możesz użyć tego polecenia, shopt -s dotglobaby zmienić zachowanie *tak, aby oprócz podobnych plików regfile1również pasowały .dotfile1.

fragment strony bashman

dotglob If set, bash includes filenames beginning with a `.' in the results 
        of pathname expansion.

Przykład:

$ shopt -s dotglob
$ echo *
.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3

Możesz przywrócić to zachowanie za pomocą tego polecenia:

$ shopt -u dotglob
$ echo *
regdir1 regdir2 regfile1 regfile2 regfile3

Twoja sytuacja?

Dla ciebie mówisz cp, że chcesz skopiować wszystkie pliki, które pasują do wzorca *, i nie ma żadnych plików.

$ cp foo/.* .

Możesz to zrobić, jeśli chcesz wszystko w foofolderze:

$ cp foo .

Lub możesz wyrazić się jasno:

$ cp foot/.* foo/* .

Bardziej kompaktowa forma wykorzystująca rozszerzenie nawiasów w bash:

$ cp foo/{.,}* .

W dowolnym momencie możesz użyć tej echosztuczki, aby zobaczyć, jakie są proponowane wzorce plików (to fantazyjne określenie tego, co jest częścią gwiazdy).

$ echo {.,}*
. .. .dotdir1 .dotdir2 .dotfile1 .dotfile2 abc regdir1 regdir2 regfile1 regfile2 regfile3

Nawiasem mówiąc, jeśli zamierzasz skopiować katalog plików + inne katalogi, zwykle chcesz to zrobić rekurencyjnie, to jest -Rprzejście do cp:

$ cp -R foo/. .
slm
źródło
1
Możesz wspomnieć o użyciu shopt -s dotglob, echo *a następnie daje:.dotdir1 .dotdir2 .dotfile1 .dotfile2 regdir1 regdir2 regfile1 regfile2 regfile3
Drav Sloan
@DravSloan - dzięki za sugestię. Dodano to.
slm
cp -r foo .zazwyczaj nie będzie działać, ponieważ cpodmówi kopiowania foonad sobą, prawdopodobnie miałeś na myśli cp -R foo/. .. (zwróć uwagę, że cp -Rjest to standard).
Stéphane Chazelas,
1
Zauważ też, że (całkiem rozsądnie) zshnie obejmuje .i nie ..rozwija .*. W zshprzypadku, gdy wzorzec nie pasuje, polecenie zostanie przerwane (całkiem rozsądnie ponownie), więc w ogólnym przypadku cp foo/{,.}* .zakończy się niepowodzeniem, jeśli nie będzie żadnych ukrytych plików lub nie ukrytych plików.
Stéphane Chazelas,
7
Ta odpowiedź dotyczy tylko bash. Pytający używa zsh, gdzie odpowiedź jest o wiele prostsza i shoptnie istnieje.
Gilles „SO- przestań być zły”,
31

Za pomocą zsh, typowym sposobem jest użycie D kwalifikatora glob (aby dołączyć pliki [D] ot):

cp foo/*(D) .

Zauważ, że z lub bez Dglobs zsh nigdy nie zawiera .ani ..(jak można się spodziewać).

Stéphane Chazelas
źródło
4

Powłoka traktuje te pliki jako ukryte, kiedy rozpoznaje *znak, więc cpnie otrzymuje żadnej z tych nazw plików jako argumentów.

Możesz je skopiować, wyraźnie zaznaczając cp foo/.* .

powtórna rozgrywka
źródło
1

Jeśli chcesz skopiować wszystkie pliki i katalogi z jednego miejsca do drugiego, możesz użyć standardowego rsyncpolecenia. W podanym powyżej przykładzie:

mkdir foo && touch foo/.test
rsync -a foo/ .

będzie rekurencyjnie kopiować całą zawartość foo, w tym ukryte pliki i ukryte katalogi, do bieżącego katalogu. Końcowy ukośnik na końcu foo/jest ważny dla rsync; z nim fookopiowana jest tylko zawartość pliku, bez niego rsync również skopiuje foo. Na przykład:-

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' 

Istnieje wiele innych opcji dostrojenia rsync, w tym kopiowanie między komputerami.

Rob Swarbrick
źródło
1

Zsh Stephane Chazelas za odpowiedź jest poprawna dla jednego wyrazu z glob w nim. Jeśli jednak chcesz ustawić go domyślnie dla wszystkich wyrażeń, możesz użyć

setopt GLOB_DOTS

Umieść go w swoim, ~/.zshrcaby stał się trwały.

Krogulec
źródło