Testowałem cp
za pomocą następujących poleceń:
$ ls
first.html second.html third.html
$ cat first.html
first
$ cat second.html
second
$ cat third.html
third
Następnie kopiuję first.html
do second.html
:
$ cp first.html second.html
$ cat second.html
first
Plik second.html
jest dyskretnie nadpisywany bez żadnych błędów. Jeśli jednak zrobię to w graficznym graficznym interfejsie użytkownika, przeciągając i upuszczając plik o tej samej nazwie, zostanie on dodany first1.html
automatycznie. Pozwala to uniknąć przypadkowego zastąpienia istniejącego pliku.
Dlaczego cp
zamiast tego po cichu nadpisywać pliki?
cp
docp -i
lub podobny, ponieważ będziesz przyzwyczaić do posiadania siatki bezpieczeństwa, systemy, w których nie jest dostępne co (większość z nich), które znacznie bardziej ryzykowne. Lepiej nauczyć się rutynowocp -i
itp., Jeśli tak wolisz.Odpowiedzi:
Domyślne zachowanie nadpisywania
cp
jest określone w POSIX.Kiedy pisano specyfikację POSIX, istniała już duża liczba skryptów, z wbudowanym założeniem domyślnego zachowania nadpisywania. Wiele z tych skryptów zaprojektowano do działania bez bezpośredniej obecności użytkownika, np. Jako zadania cron lub inne zadania w tle. Zmiana zachowania złamałaby je. Przejrzenie i zmodyfikowanie ich wszystkich w celu dodania opcji wymuszania nadpisywania wszędzie tam, gdzie było to potrzebne, zostało prawdopodobnie uznane za ogromne zadanie przy minimalnych korzyściach.
Ponadto linia poleceń systemu Unix zawsze była zaprojektowana tak, aby umożliwić doświadczonemu użytkownikowi wydajną pracę, nawet kosztem ciężkiej krzywej uczenia się dla początkującego. Kiedy użytkownik wprowadza polecenie, komputer oczekuje, że użytkownik naprawdę to rozumie, bez żadnego odgadywania; obowiązkiem użytkownika jest ostrożność w przypadku potencjalnie niszczących poleceń.
Kiedy opracowano oryginalny Unix, systemy miały tak mało pamięci i pamięci masowej w porównaniu do współczesnych komputerów, że zastępują ostrzeżenia i monity prawdopodobnie były postrzegane jako marnotrawstwo i niepotrzebne luksusy.
Kiedy pisano standard POSIX, precedens został mocno ustalony, a autorzy standardu doskonale zdawali sobie sprawę z zalet niezniszczenia kompatybilności wstecznej .
Poza tym, jak opisali inni, każdy użytkownik może dodawać / włączać te funkcje dla siebie, używając aliasów powłoki lub nawet budując
cp
polecenie zastępowania i modyfikując je,$PATH
aby znaleźć zamiennik przed standardowym poleceniem systemowym, i uzyskać w ten sposób siatkę bezpieczeństwa, jeśli pożądany.Ale jeśli to zrobisz, przekonasz się, że stwarzasz zagrożenie dla siebie. Jeśli
cp
polecenie zachowuje się w jeden sposób, gdy jest używane interaktywnie, a w inny sposób, gdy jest wywoływane ze skryptu, możesz nie pamiętać, że istnieje różnica. W innym systemie możesz być nieostrożny, ponieważ przyzwyczaiłeś się do ostrzeżeń i podpowiedzi w swoim własnym systemie.Jeśli zachowanie w skryptach nadal będzie zgodne ze standardem POSIX, prawdopodobnie przyzwyczaisz się do podpowiedzi w trybie interaktywnym, a następnie napiszesz skrypt, który wykonuje masowe kopiowanie - i wtedy znowu zauważysz, że coś przypadkowo nadpisałeś.
Jeśli wymuszasz także wyświetlanie monitów w skryptach, co zrobi polecenie, gdy uruchomisz je w kontekście, w którym nie ma użytkownika, np. Procesy w tle lub zadania cron? Czy skrypt zawiesza się, przerywa lub zastępuje?
Wieszanie lub przerywanie oznacza, że zadanie, które miało zostać wykonane automatycznie, nie zostanie wykonane. Brak nadpisania może czasami powodować sam problem: na przykład może spowodować, że stare dane zostaną przetworzone dwukrotnie przez inny system, zamiast zostać zastąpione aktualnymi danymi.
Duża część mocy wiersza poleceń wynika z faktu, że gdy już wiesz, jak coś zrobić w wierszu polecenia, domyślnie wiesz również, jak to zrobić automatycznie przez skrypt . Jest to jednak prawdą tylko wtedy, gdy polecenia, których używasz interaktywnie, działają dokładnie tak samo, gdy są wywoływane w kontekście skryptu. Wszelkie znaczące różnice w zachowaniu między użyciem interaktywnym a użyciem skryptowym stworzą rodzaj dysonansu poznawczego, który jest denerwujący dla zaawansowanego użytkownika.
źródło
rm -rf
jest tak skuteczny, nawet jeśli tak naprawdę nie chciałeś uruchomić go w swoim katalogu domowym ...cp
pochodzi z początku Uniksa. Było to na długo przed napisaniem standardu Posix. Rzeczywiście: Posix właśnie sformalizował istniejące zachowaniecp
w tym zakresie.Rozmawiamy wokół Epoki (1970-01-01), kiedy mężczyźni byli prawdziwymi mężczyznami, kobiety były prawdziwymi kobietami i futrzastymi małymi stworzeniami ... (dygresję). W tych czasach dodanie dodatkowego kodu spowodowało, że program stał się większy. To był wtedy problem, ponieważ pierwszym komputerem z systemem Unix był PDP-7 (z możliwością aktualizacji do 144 KB pamięci RAM!). Więc rzeczy były małe, wydajne, bez zabezpieczeń.
Tak więc w tamtych czasach musieliście wiedzieć, co robicie, ponieważ komputer po prostu nie był w stanie powstrzymać cię przed zrobieniem czegoś, czego później żałowałeś.
(Jest ładny rysunek Zevara; wyszukaj „zevar cerveaux assiste par ordinateur”, aby znaleźć ewolucję komputera. Lub spróbuj http://perinet.blogspirit.com/archive/2012/02/12/zevar-et- cointe.html tak długo, jak istnieje
Dla naprawdę zainteresowanych (widziałem spekulacje w komentarzach): Oryginał
cp
na pierwszym Uniksie zawierał około dwóch stron kodu asemblera (C przyszedł później). Odpowiednią częścią było:(Więc trudny
sys creat
)I, gdy już to jesteśmy: używana wersja 2 Uniksa (fragment kodu)
co jest również trudne
creat
bez testów i zabezpieczeń. Zauważ, że kod C dla V2 Unixcp
to mniej niż 55 linii!źródło
cp
właśnie edytowanegoopen
miejsca docelowegoO_CREAT | O_TRUNC
wykonały pętlęread
/write
; pewnie, z nowoczesnymcp
jest tyle pokręteł, że w zasadzie musistat
najpierw spróbować dotrzeć do miejsca docelowego, i może najpierw łatwo sprawdzić istnienie (i robi to zcp -i
/cp -n
), ale jeśli oczekiwania zostałyby ustalone na podstawie oryginalnychcp
narzędzi bez kości , zmieniając to zachowanie niepotrzebnie łamałby istniejące skrypty. To nie jest tak, jak nowoczesne powłoki, zalias
których nie można po prostu ustawićcp -i
domyślnie interaktywnego użycia.creat
zdarza się, że jest to odpowiednikopen
+O_CREAT | O_TRUNC
), ale brakO_EXCL
wyjaśnia, dlaczego nie byłoby tak łatwo obsługiwać istniejące pliki; próba zrobienia tego byłaby z natury ryzykowna (w zasadzie musiałbyśopen
/stat
sprawdzić istnienie, a następnie użyćcreat
, ale na dużych współużytkowanych systemach zawsze jest to możliwe, zanim dotrzeszcreat
, ktoś utworzył plik, a teraz wysadziłeś i tak dalej). Również może nadpisać bezwarunkowo.Ponieważ te polecenia są również przeznaczone do użycia w skryptach, być może uruchamianych bez jakiegokolwiek nadzoru ze strony człowieka, a także dlatego, że istnieje wiele przypadków, w których naprawdę chcesz zastąpić cel (filozofia powłok Linuxa polega na tym, że człowiek wie, co ona robi)
Istnieje jeszcze kilka zabezpieczeń:
cp
ma-n
|--no-clobber
opcjacp
, narzekasz, że ostatni nie jest katalogiem.źródło
Ten komentarz brzmi jak pytanie o ogólną zasadę projektowania. Często pytania na ten temat są bardzo subiektywne i nie jesteśmy w stanie napisać właściwej odpowiedzi. Ostrzegamy, że w tej sprawie możemy zamknąć pytania.
Czasami mamy wyjaśnienie oryginalnego wyboru projektu, ponieważ deweloperzy napisali o nich. Ale nie mam tak ładnej odpowiedzi na to pytanie.
Dlaczego
cp
jest tak zaprojektowany?Problem w tym, że Unix ma ponad 40 lat.
Jeśli tworzysz teraz nowy system, możesz dokonać różnych wyborów projektowych. Ale zmiana Uniksa złamałaby istniejące skrypty, jak wspomniano w innych odpowiedziach.
Dlaczego został
cp
zaprojektowany do dyskretnego nadpisywania istniejących plików?Krótka odpowiedź brzmi „nie wiem” :-).
Zrozum, że
cp
to tylko jeden problem. Myślę, że żaden z oryginalnych programów poleceń nie był chroniony przed nadpisywaniem lub usuwaniem plików. Powłoka ma podobny problem podczas przekierowywania danych wyjściowych:To polecenie również po cichu zastępuje
second.html
.Interesuje mnie, w jaki sposób można przeprojektować wszystkie te programy. Może to wymagać dodatkowej złożoności.
Myślę, że jest to część wyjaśnienia: wczesny Unix podkreślał proste implementacje . Aby uzyskać bardziej szczegółowe wyjaśnienie, patrz „gorsze jest lepsze”, połączone na końcu tej odpowiedzi.
Możesz zmienić,
> second.html
aby zatrzymał się z błędem, jeślisecond.html
już istnieje. Jednak, jak już wspomnieliśmy, czasami użytkownik nie chce, aby zastąpić istniejący plik. Na przykład może budować złożone polecenie, próbując kilka razy, aż zrobi to, co chce.Użytkownik może uruchomić
rm second.html
najpierw, jeśli zajdzie taka potrzeba. To może być dobry kompromis! Ma kilka własnych wad.rm
. Więc chciałbym też uczynićrm
bezpieczniejszym. Ale jak? Jeślirm
pokażemy każdą nazwę pliku i poprosimy użytkownika o potwierdzenie, musi ona teraz napisać trzy wiersze poleceń zamiast jednego. Ponadto, jeśli będzie musiała to robić zbyt często, przyzwyczai się i wpisze „y”, aby potwierdzić bez zastanowienia. Może to być bardzo denerwujące i nadal niebezpieczne.W nowoczesnym systemie zalecam zainstalowanie
trash
polecenia i używanie go zamiast, gdy torm
możliwe. Wprowadzenie pamięci Trash było świetnym pomysłem np. Dla graficznego komputera dla jednego użytkownika .Myślę, że ważne jest również zrozumienie ograniczeń oryginalnego sprzętu uniksowego - ograniczona pamięć RAM i miejsce na dysku, wydajność wyświetlana na wolnych drukarkach, a także oprogramowanie systemowe i programistyczne.
Zauważ, że oryginalny Uniks nie miał uzupełniania tabulatorami , aby szybko wypełnić nazwę pliku dla
rm
polecenia. (Również oryginalna powłoka Bourne'a nie ma historii poleceń, np. Kiedy używasz klawisza strzałki w górębash
).Przy wyjściu drukarki, należy użyć edytora linii opartej
ed
. Jest to trudniejsze do nauczenia niż wizualny edytor tekstu. Musisz wydrukować kilka bieżących wierszy, zdecydować, w jaki sposób chcesz je zmienić i wpisać polecenie edycji.Użycie
> second.html
jest trochę jak użycie polecenia w edytorze linii. Efekt, jaki ma, zależy od bieżącego stanu. (Jeślisecond.html
już istnieje, jego zawartość zostanie odrzucona). Jeśli użytkownik nie jest pewien aktualnego stanu, oczekuje się, że uruchomi sięls
lubls second.html
pierwszy.„Proste wdrożenie” jako zasada projektowania
Istnieje popularna interpretacja projektu Uniksa, która zaczyna się:
źródło
cp
„problemem”? Interaktywne proszenie o pozwolenie lub niepowodzenie może być równie dużym „problemem” jak to.cat first.html second.html > first.html
da wynikfirst.html
nadpisaniasecond.html
tylko zawartością . Oryginalna zawartość zostaje utracona na zawsze.Projekt „cp” sięga pierwotnego projektu Uniksa. Istotnie, istniała spójna filozofia stojąca za projektem Uniksa, która była nieco mniej niż w połowie żartobliwie określana jako Worse-is-Better * .
Podstawową ideą jest to, że uproszczenie kodu jest tak naprawdę ważniejszym zagadnieniem projektowym niż posiadanie idealnego interfejsu lub „robienie właściwej rzeczy”.
( moje podkreślenie )
Pamiętając, że to był 1970 rok, użyłem „Chcę skopiować ten plik tylko wtedy, gdy jeszcze nie istnieje” byłby dość rzadkim przypadkiem użycia przez osobę wykonującą kopię. Jeśli tego właśnie chciałeś, będziesz w stanie sprawdzić przed kopią, a to może nawet zostać skrypty.
Co do tego, dlaczego system operacyjny z takim podejściem projektowym okazał się tym, który zwyciężył nad wszystkimi innymi systemami operacyjnymi budowanymi w tym czasie, autor eseju również miał na to teorię.
* - lub to, co autor, ale nikt inny, nie nazwał „podejściem z New Jersey” .
źródło
creat()
vsopen()
.open()
Nie może utworzyć plik, jeśli nie istnieje. To trwa tylko 0/1/2 dla odczytu / zapisu / oba. To nie jest jeszcze podjąćO_CREAT
, i nie maO_EXCL
).Głównym powodem jest to, że GUI jest z definicji interaktywne, podczas gdy plik binarny
/bin/cp
jest po prostu programem, który można wywoływać z różnych miejsc, na przykład z GUI ;-). Założę się, że nawet dziś większość połączeń do/bin/cp
nie będzie z prawdziwego terminala z użytkownikiem wpisującym polecenie powłoki, ale raczej z serwera HTTP, systemu pocztowego lub NAS. Wbudowana ochrona przed błędami użytkownika ma sens w interaktywnym środowisku; mniej w prostym pliku binarnym. Na przykład, GUI najprawdopodobniej zadzwoni/bin/cp
w tle, aby wykonać rzeczywiste operacje i będzie musiał poradzić sobie z pytaniami dotyczącymi bezpieczeństwa w standardzie, nawet jeśli tylko zapytał użytkownika!Zauważ, że od pierwszego dnia było prawie banalnie napisać bezpieczne opakowanie,
/bin/cp
jeśli jest to pożądane. Filozofią * nix jest zapewnienie użytkownikom prostych elementów składowych: z nich/bin/cp
jest jeden.źródło