Jak skopiować katalog rekurencyjnie za pomocą linków twardych dla każdego pliku

52

Chcę utworzyć „kopię” drzewa katalogów, w którym każdy plik jest dowiązaniem twardym do oryginalnego pliku

Przykład: Mam strukturę katalogów:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Oto oczekiwany wynik, „kopia” drzewa katalogów, w którym każdy plik jest dowiązaniem twardym do oryginalnego pliku:

dirB/            #  normal directory
dirB/file1       #  hardlink to dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  hardlink to dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  hardlink to dirA/y/file3
Gudmundur Orn
źródło

Odpowiedzi:

50

W Linuksie (a dokładniej z GNU i busyboximplementacjami cptak typowymi w systemach, które mają Linuksa jako jądro) i najnowszym FreeBSD, oto jak to zrobić:

cp -al dirA dirB

Aby uzyskać bardziej przenośne rozwiązanie, zobacz odpowiedź przy użyciu pax i cpio autorstwa Stéphane Chazelas

Gudmundur Orn
źródło
Zauważ, że podobnie jak paxwe FreeBSD, cp -anie łączy dowiązań symbolicznych.
Stéphane Chazelas
Należy pamiętać, że twarde łącza nie działają w przypadku oddzielnych montowań systemu plików.
Dave
24

POSIXly, używałbyś paxw trybie odczytu i zapisu z -lopcją:

pax -rwlpe -s /A/B/ dirA .

( -peZachowuje wszystkie możliwe atrybuty plików (w tym przypadku jedynie katalogi), które są skopiowane, jak GNU cp„s -arobi).

Teraz, chociaż standardowe , to polecenie niekoniecznie jest bardzo przenośne .

Po pierwsze, wiele systemów opartych na GNU / Linux nie zawiera paxdomyślnie (chociaż nie jest to opcjonalne narzędzie POSIX).

Następnie szereg błędów i niezgodności z kilkoma implementacjami powoduje szereg problemów z tym kodem.

  • z powodu błędu Solaris 10 pax(przynajmniej) nie działa, gdy jest używany -rwlw połączeniu z -s. Z jakiegoś powodu wydaje się, że stosuje podstawienie zarówno do oryginalnej, jak i skopiowanej ścieżki. Tak więc powyżej spróbowałby zrobić coś link("dirB/file", "dirB/file")zamiast link("dirA/file", "dirB/file").
  • na FreeBSD paxnie tworzy twardych dowiązań dla plików typu dowiązanie symboliczne (zachowanie dozwolone przez POSIX). Nie tylko to, ale również stosuje się substytucję do celów dowiązania (zachowanie nie dozwolonych przez POSIX). Tak na przykład, jeśli istnieje foo -> AAdowiązanie w dirA, stanie foo -> BAsię dirB.

Ponadto, jeśli chcesz zrobić to samo, ale z dowolnych ścieżek plik, którego zawartość jest przechowywana w $srci $dstważne jest, aby uświadomić sobie, że pax -rwl -- "$src" "$dst"tworzy pełną strukturę katalogów $srcwewnętrznej $dst(który musi istnieć i być katalogiem). Na przykład, jeśli $srcjest foo/bar, to $dst/foo/barjest tworzone.

Jeśli zamiast tego chcesz $dstbyć kopią $src, najłatwiej jest to zrobić:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")

(co obejdzie również większość wyżej wymienionych problemów, ale zawiedzie, jeśli bezwzględna ścieżka $dstkońca kończy się na znakach nowej linii).

Teraz to nie pomoże w systemach GNU / Linux, gdzie nie ma pax.

Warto zauważyć, że paxzostał stworzony przez POSIX w celu scalenia funkcji poleceń tari cpio.

cpiojest historycznym poleceniem uniksowym (z 1977 r.) w przeciwieństwie do wynalazku POSIX, a także implementacją GNU (nie paxjedną). Tak więc, mimo że nie jest to już standardowe polecenie (choć było w SUSv2), wciąż jest bardzo powszechne i istnieje podstawowy zestaw funkcji, na których zwykle można polegać.

Odpowiednikiem pax -rwlbyłoby cpio -pl. Jednak:

  1. cpio pobiera listę plików wejściowych na stdin w przeciwieństwie do argumentów (znak nowej linii, co oznacza, że ​​nazwy plików ze znakami nowej linii nie są obsługiwane)
  2. Wszystkie pliki muszą zostać określone (zazwyczaj podajesz dane wyjściowe find( findi cpiozostały opracowane wspólnie przez te same osoby)).
  3. metadane nie są zachowywane (niektóre cpioimplementacje mają opcje zachowania niektórych, ale nic przenośnego).

Więc z cpio:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
Stéphane Chazelas
źródło
Wydaje się, że -s / A / B / jest specyficzne dla mojego przykładu. Jak byś to zrobił, gdyby nazwa katalogu źródłowego i nazwa katalogu docelowego były zmiennymi $ sourcedir i $ targetdir?
Gudmundur Orn
@GudmundurOrn, patrz edycja.
Stéphane Chazelas,
Uruchamiam to polecenie w systemie OS X i po prostu pojawia się komunikat o błędzie „pax: Nie można połączyć pliku ./a.txt z samym sobą”. Użyłem twojego polecenia dosłownie, po prostu zastępując katalog źródłowy rzeczywistą nazwą, pozostawiając / A / B i ostatnią kropkę bez zmian. Czy coś nie rozumiem?
db
@db, -s /A/Bzastępuje Asię Btak, że dirAstaje się dirB. Jeśli nazwa twojego katalogu źródłowego nie ma A, to skopiuje (link) ją nad sobą. Zobacz także resztę odpowiedzi na potencjalnie lepsze podejścia.
Stéphane Chazelas,
6

Krótka odpowiedź:

cd $source_folder
pax -rwlpe . $dest_folder
Lkraider
źródło
2

W przypadku, gdy szukasz funkcji kopiowania z hardlinkami, aby tworzyć migawki lub kopie zapasowe (wszystkich lub części) swoich plików rsnapshot.

Janis
źródło
1
To interesujące. Ale chyba twarde linki są dobrym mechanizmem migawkowym, jeśli pliki nie zostaną zmodyfikowane. Dobrze?
Gudmundur Orn
@Gudmundur Orn; To jest poprawne. Narzędzie wspomniane w mojej odpowiedzi utworzy nową migawkę w taki sposób, że pliki będą unikalne; tzn. istniejące (niezmodyfikowane) pliki zostaną utworzone jako łącza twarde, a nowe pliki (lub zmodyfikowane wersje istniejących plików) zostaną utworzone jako nowe pliki. W konsekwencji będziesz miał najmniejszą redundancję.
Janis
0

Odpowiedź @ gudmundur-orn jest poprawna, ale jeśli korzystasz z BtrFS w systemie Linux, cp a --reflink=auto dirA dirBpowinieneś załatwić sprawę , z tą różnicą, że pliki są różne, a zmiana jednego nie zmienia drugiego. Możesz osiągnąć w większości to samo z cp -ckomputerem Mac z APFS ( autojeśli to niemożliwe, zrobi pełną kopię, nie -cpowiedzie się).

Każdy system plików COW powinien być w stanie to zrobić, ale dostawcy nie uzgodnili standardowej opcji wiersza poleceń.

wariat
źródło