cp zachowuje się dziwnie kiedy. (kropka) lub .. (kropka kropka) to katalog źródłowy

15

Ta odpowiedź pokazuje, że można skopiować wszystkie pliki - w tym ukryte - z katalogu srcdo katalogu w następujący destsposób:

mkdir dest
cp -r src/. dest

W odpowiedzi ani w komentarzach nie ma wyjaśnienia, dlaczego tak naprawdę działa, i nikt nie wydaje się na to znaleźć dokumentacji.

Wypróbowałem kilka rzeczy. Po pierwsze, normalny przypadek:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src dest
$ ls -A dest
dest_file  src

Następnie /.na końcu:

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/. dest
$ ls -A dest
dest_file  .dotfile  src_dir  src_file

Zachowuje się to podobnie *, ale także kopiuje ukryte pliki.

$ mkdir src src/src_dir dest && touch src/src_file src/.dotfile dest/dest_file
$ cp -r src/* dest
$ ls -A dest
dest_file  src_dir  src_file

.i ..są odpowiednimi linkami, jak wyjaśniono tutaj , podobnie jak sam wpis katalogu.

Skąd się bierze to zachowanie i gdzie jest to udokumentowane?

iFreilicht
źródło
3
Co masz na myśli, że nikt nie może znaleźć dokumentacji? cpOdniesienia wyraźnie wyjaśnia, jak cp -Rdziała. .i ..są katalogami, tak jak wszystkie inne katalogi, nie ma w nich nic magicznego lub tajemniczego.
AlexP,
2
@AlexP Zredagowałem odpowiedź, aby była jaśniejsza. Chodzi o to .i ..nie zachowuj się jak inne katalogi.
iFreilicht,
Próbowałem wyjaśnić, dlaczego to działa w Jak skopiować folder rekurencyjnie w idempotentny sposób za pomocą cp
roaima

Odpowiedzi:

27

Zachowanie jest logicznym wynikiem udokumentowanego algorytmu dla cp -R. Patrz POSIX , krok 2f:

Pliki w katalogu plik_źródłowy zostaną skopiowane do katalogu plik_zdefiniowany , wykonując cztery kroki (1–4) wymienione tutaj wraz z plikami jako pliki_źródłowe .

.i ..są katalogami, odpowiednio bieżącym i nadrzędnym. Żadne z nich nie jest wyjątkowe, jeśli chodzi o powłokę, więc żadne z nich nie dotyczy rozszerzenia, a katalog zostanie skopiowany wraz z ukrytymi plikami. *, z drugiej strony, zostanie rozwinięty do listy plików, i tutaj filtrowane są ukryte pliki.

src/.jest bieżącym katalogiem wewnątrz src, który jest srcsam; src/src_dir/..to src_dirkatalog nadrzędny, który również jest src. Więc z zewnątrz src, jeśli srcjest katalogiem, określenie src/.lub src/src_dir/..jako plik źródłowy cpsą równoważne, i skopiuj zawartość src, w tym ukryte pliki.

Chodzi o src/.to, że zakończy się niepowodzeniem, jeśli srcnie jest katalogiem (lub dowiązaniem symbolicznym do katalogu), podczas gdy srcnie. Skopiuje również srctylko zawartość , bez kopiowania src; odpowiada to również dokumentacji:

Jeśli cel istnieje i nazywa istniejący katalog, nazwą odpowiedniej ścieżki docelowej dla każdego pliku w hierarchii plików będzie konkatenacja celu , pojedynczy znak ukośnika, jeśli cel nie zakończył się ukośnikiem, oraz nazwa ścieżki do pliku względnego do katalogu zawierającego plik_źródłowy .

Więc cp -R src/. destkopiuje zawartość srcdo dest/.(plik źródłowy jest .w src), podczas gdy cp -R src destkopiuje zawartość srcdo dest/src(plik źródłowy jest src).

Innym sposobem myślenia o tym jest porównanie kopiowania src/src_diri src/.zamiast porównywania src/.i src. .zachowuje się tak jak src_dirw poprzednim przypadku.

Stephen Kitt
źródło
Ale to nie działa w ten sam sposób. Określenie srcspowoduje skopiowanie katalogu dest, src/.skopiowanie zawartości. Spróbuję to wyjaśnić w pytaniu.
iFreilicht,
Tam myślę, że to odpowiada na twoje podstawowe pytanie.
Stephen Kitt,
1
@ Stéphane OP porównuje kopiowanie src/.i src/*(uwaga, nie src/.* ); src/*nie zawiera ukrytych plików, jeśli globbing je zignoruje ...
Stephen Kitt
1
Hmm, „katalog zawierający plik_źródłowy ”. Cóż, oczywiście srczawiera, src/.ale oznacza to, że katalog zawierający katalog zależy od tego, jak go nazwiesz. Oczywiście istnienie .łączy w pewnym sensie oznacza, że ​​wszystkie katalogi zawierają siebie, ale może to nie być intuicyjne dla wszystkich. Zamiast tego zachowania można również pokusić się o założenie, że „katalog zawierający katalog foo” byłby określony przez foo/.., w którym to przypadku nie miałoby znaczenia, czy odnosimy się do : foolub foo/.wynikowy katalog zawierający byłby taki sam.
ilkkachu
1
To znaczy, że rozróżnienie między fooi foo/.wydaje się nieco delikatne, ale nie mam nic przeciwko, uważam to również za nieco zabawne.
ilkkachu
1

Po uruchomieniu cp -R src/foo destdostaniesz dest/foo. Więc jeśli katalog dest/foonie istnieje, cputworzy go, a następnie skopiuje zawartość src/foodo dest/foo.

Po uruchomieniu cp -R src/. dest, cpwidzi, że dest/.istnieje, i to jest to po prostu kwestia kopiując zawartość src/.do dest/..

Kiedy myślisz o tym, jak kopiując katalog o nazwie .od srci połączenie jej z istniejącą zawartość katalogu dest/., to sensu.

telcoM
źródło