Bardzo dobrze rozumiem pojęcie linków twardych i cp
kilkakrotnie czytałem strony podręcznika dla podstawowych narzędzi, takich jak --- a nawet najnowsze specyfikacje POSIX. Wciąż byłem zaskoczony obserwowaniem następującego zachowania:
$ echo john > john
$ cp -l john paul
$ echo george > george
W tym momencie john
i paul
będzie miał taką samą zawartość iwęzeł (i), i george
będą się różniły w obu aspektach. Teraz wykonujemy:
$ cp george paul
W tym momencie spodziewałem się george
i będę paul
miał różne numery i-węzłów, ale tę samą treść --- to oczekiwanie zostało spełnione --- ale spodziewałem się również, że będę paul
mieć inny numer john
i- węzła i john
nadal będę mieć zawartość john
. Byłem tam zaskoczony. Okazuje się, że skopiowanie pliku do ścieżki docelowej paul
powoduje również zainstalowanie tego samego pliku (tego samego i-węzła) na wszystkich innych ścieżkach docelowych, które współużytkują paul
i-węzeł. Myślałem, że cp
tworzy nowy plik i przenosi go do miejsca, które poprzednio zajmował stary plik paul
. Zamiast tego wydaje się, że otwiera istniejący plik paul
, obcina go i piszegeorge
zawartość tego istniejącego pliku. W związku z tym wszystkie „inne” pliki z tym samym i-węzłem otrzymują jednocześnie „swoją” treść.
Ok, to jest systematyczne zachowanie i teraz, kiedy wiem, że mogę się tego spodziewać, mogę wymyślić, jak go obejść, lub odpowiednio go wykorzystać. Co mnie zastanawia, gdzie miałem udokumentować to zachowanie? Byłbym zaskoczony, gdyby nie zostało to udokumentowane gdzieś w dokumentach, które już przeglądałem. Ale najwyraźniej mi tego brakowało i nie mogę teraz znaleźć źródła, które omawia takie zachowanie.
cp
dokumenty, które zastępują plik docelowy, jeśli plik docelowy jest już obecny. Masz rację, że nie określa ono szczegółowo, co oznacza „nadpisanie”, ale zdecydowanie mówi „nadpisuj”, a nie „zastępuj”. Jeśli chcesz być pedantyczny, możesz argumentować, że „nadpisywanie” jest dokładnie tym, cocp
działa, a oczekiwane zachowanie można by właściwie nazwać „zamień”.Zauważ też, że gdyby
cp
„zastąpić” wcześniej istniejące pliki docelowe, można to uznać za zaskakujące lub niepoprawne, prawdopodobnie więcej niż „nadpisywanie”. Na przykład:cp
najpierw usuniesz stary plik, a następnie utworzysz nowy, będzie pewien przedział czasu, w którym plik będzie nieobecny, co byłoby zaskakujące.cp
najpierw utworzysz plik tymczasowy, a następnie przeniesiesz go na miejsce, prawdopodobnie powinien to udokumentować, ze względu na fakt, że takie pliki tymczasowe o dziwnych nazwach byłyby czasami zauważane ... ale tak nie jest.cp
nie można utworzyć nowego pliku w tym samym katalogu, co stary plik ze względu na uprawnienia, byłoby to niefortunne (szczególnie, jeśli stary plik został już usunięty).cp
a użytkownik działającycp
nie był, nieroot
byłoby możliwe dopasowanie właściciela i uprawnień nowego pliku do uprawnień nowego pliku.cp
których nie wie, to zostałyby utracone w kopii. W dzisiejszych czasach implementacjecp
powinny niezawodnie rozumieć takie cechy, jak rozszerzone atrybuty, ale nie zawsze tak było. Są też inne rzeczy, takie jak rozwidlenia zasobów MacOS lub, w przypadku zdalnych systemów plików, w zasadzie wszystko.Podsumowując: teraz wiesz, co
cp
naprawdę robi. Już nigdy nie będziesz zaskoczony! Szczerze mówiąc, myślę, że to samo mogło mi się przydarzyć wiele lat temu.źródło
man
strony dla wersjicp
BSD (przynajmniej OSX) i Gnucp
nie są tak jednoznaczne na temat „nadpisywania”. Tego słowa używa się tylko w komentarzach do opcji-i
i-n
. Strona Gnu jest szczególnie nieinformacyjna, począwszy od stronyCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
BSD / Mac, przynajmniej mówiIn the first synopsis form, the cp utility copies the contents of the source_file to the target_file.
‘cp’ copies files (or, optionally, directories). The copy is completely independent of the original.
Widzę, że standard POSIX 2013 określa obserwowane zachowanie . To mówi:
źródło
cp
że da podobne wynikimv
i zerwie wszelkie twarde linki, których częścią była dest. Ale teraz, gdy o tym myślę, oznaczałoby to, że musiałby konkretnieunlink(2)
cel (cp -f
) lub utworzyć tymczasowo inną nazwę, a potemrename(2)
to. Prostą implementacją jest po prostu otwarcie pliku do zastąpienia, czego wymaga POSIX. Jest to odpowiednikcat src > dest
Jeśli możesz powiedzieć: „skopiowanie pliku do ścieżki docelowej powoduje
paul
również skopiowanie tego samego pliku (tego samego i-węzła) do wszystkich innych ścieżek docelowychpaul
i-węzła udziału ”. Przykro mi to powiedzieć, że nie rozumiesz pojęcia twarde linki bardzo dobrze. Jeśli dam jabłko Sir McCartneyowi, dam jabłko Paulowi i jabłko partnerowi Johna Lennona. Ale nie rozdałem trzech jabłek; Dałem jabłko osobie, która ma wiele nazwisk / tytułów / deskryptorów.Podobnie, kiedy kopiujesz
george
dopaul
, nie kopiujesz również dojohn
. Zamiast tego kopiujeszgeorge
dane do pliku, którego i-węzeł wskazujepaul
pozycja katalogu.Krok po kroku: kiedy to zrobisz
utworzyłeś nowy plik (zakładając, że
john
w tym katalogu nie było już pliku o nazwie ). Lub, mówiąc ściślej, zakłada to, że nie było już pozycji katalogu o nazwiejohn
w tym katalogu (ponieważ, ściśle mówiąc, nie ma plików w katalogach; tylko wpisy katalogu, które wskazują na i-węzły). Po tym jak to zrobiszlub
nie utworzyłeś nowego pliku; zamiast tego nadałeś istniejącemu plikowi nową nazwę. Masz teraz plik o dwóch nazwach:
john
ipaul
. A kiedy mówisznadpisujesz ten plik . Fakt, że ma dwie nazwy, nie ma znaczenia; może mieć 42 nazwy, być może w miejscach, do których nawet nie masz dostępu, a to polecenie nie kopiuje
george\n
danych do wszystkich tych nazw (ścieżek); po prostu kopiuje dane do jednego pliku, który ma wiele nazw.źródło
john
ipaul
zacznij od dwóch ścieżek do tego samego pliku. Ale to był najłatwiejszy sposób na wyrażenie siebie. Nie sądzę, że samo pojęcie twardego linku, właściwie rozumiane, dyktuje jedno z dwóch zachowań dlacp
(bez-l
).