Różnica między cat i „>”, aby wyzerować plik

23

Czy te dwa polecenia różnią się w kwestii zerowania plików? Czy ten drugi sposób jest krótszy od pierwszego? Co dzieje się za kulisami?

Obie

$ cat /dev/null > file.txt

$ > file.txt 

wydajność

-rw-r--r--  1 user  wheel  0 May 18 10:33 file.txt
KM.
źródło

Odpowiedzi:

28

cat /dev/null > file.txtto bezużyteczne użycie kota .

Zasadniczo cat /dev/nullpo prostu powoduje, że catnic nie jest generowane. Tak, to działa, ale wielu z nich nie lubi, ponieważ powoduje wywołanie zewnętrznego procesu, który nie jest konieczny.
Jest to jedna z tych rzeczy, które są wspólne, ponieważ są wspólne.

Użycie just > file.txtbędzie działać na większości powłok, ale nie jest całkowicie przenośne. Jeśli chcesz być całkowicie przenośny, poniższe są dobrą alternatywą:

true > file.txt
: > file.txt

Zarówno :a truewyjście żadnych danych i są powłoki builtins (podczas gdy catjest narzędzie zewnętrzne), a więc, że są lżejsze i bardziej „właściwa”.

 

Aktualizacja:

Jak wspomniał Tylerl w swoim komentarzu, istnieje również >| file.txtskładnia.

Większość powłok ma ustawienie, które uniemożliwi im obcięcie istniejącego pliku przez >. Musisz użyć >|zamiast tego. Ma to na celu zapobieganie błędom ludzkim, gdy naprawdę chcesz dołączyć >>. Możesz włączyć zachowanie za pomocą set -C.

Tak więc myślę, że najprostszą, najodpowiedniejszą i najbardziej przenośną metodą obcinania pliku byłoby:

:>| file.txt
Patrick
źródło
2
Polecenie dwukropek jest zdefiniowane w POSIX . Jest to operacja zerowa, która istnieje w celu rozszerzenia argumentów wiersza poleceń.
kojiro
3
LOL, „nadużycie kota”
KM.
2
@kojiro :jest również wymagane przez POSIX do wbudowania, a tak naprawdę różni się od truetego, że jest uważane za wbudowane „specjalne” .
jw013
2
nie zapomnij o noclobber . >| filejest bardziej wyraźnym obcięciem.
tylerl
1
Nie truejest wymagane, aby nie było wbudowane i tradycyjnie nie było. :jest wbudowany we wszystkie muszle rodziny Bourne. :jest specjalnym wbudowanym w POSIX (więc : > filena przykład opuści powłokę, jeśli filenie może być otwarty do pisania w powłokach POSIX) i truenie jest. POSIX wspomina nawet, że :może być bardziej wydajny niż truew niektórych systemach.
Stéphane Chazelas
23

Pod względem przenośności:

                      Bourne POSIX  zsh    csh/tcsh  rc/es  fish
> file                Y      Y      N(1)   N(1)      N      N
: > file              N/Y(2) Y(3)   Y      Y(4)      N(5)   N(5)
true > file           Y(5)   Y      Y      Y(5)      Y(5)   Y(5)
cat /dev/null > file  Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
eval > file           Y(3,8) Y(3)   Y      Y(6)      Y      Y
cp /dev/null file (7) Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
printf '' > file      Y(5)   Y      Y      Y(5)      Y(5)   Y

Uwagi:

  1. z wyjątkiem emulacji shlub ksh, dla przekierowań bez polecenia, w zsh przyjmuje się polecenie domyślne (pager tylko dla przekierowania standardowego, w catprzeciwnym razie), które można dostroić za pomocą zmiennych NULLCMD i READNULLCMD. Jest to inspirowane podobną funkcją w(t)csh
  2. Przekierowania początkowo nie były wykonywane :w UnixV7, co :zostało zinterpretowane w połowie drogi między linią odniesienia komentarza a poleceniem zerowym. Później były i jak we wszystkich wbudowanych, jeśli przekierowanie nie powiedzie się, to wychodzi z powłoki.
  3. :i evalbędąc specjalnymi wbudowanymi funkcjami, jeśli przekierowanie nie powiedzie się, wychodzi z powłoki ( bashrobi to tylko w trybie POSIX).
  4. Co ciekawe, w (t)cshtym definiuje się etykietę zerową (for goto), więc goto ''tam będzie rozgałęzienie. Jeśli przekierowanie nie powiedzie się, nastąpi wyjście z powłoki.
  5. Chyba / jeżeli odpowiedni rozkaz jest dostępny $PATH( :na ogół nie jest, true, cat, cpi printfna ogół są (POSIX wymaga ich)).
  6. Jeśli przekierowanie nie powiedzie się, nastąpi wyjście z powłoki.
  7. Jeśli jednak filejest dowiązaniem symbolicznym do nieistniejącego pliku, niektóre cpimplementacje, takie jak GNU, odmówią jego utworzenia.
  8. Początkowe wersje powłoki Bourne'a nie obsługiwały jednak poleceń przekierowujących

Pod względem czytelności:

(ta sekcja jest wysoce subiektywna)

  • > file. To >zbyt przypomina podpowiedź lub komentarz. Pytanie, które zadam podczas czytania (i większość powłok narzeka na to samo), to jakie dane dokładnie przekierowujecie? .
  • : > file. :jest znany jako polecenie no-op. Czyli to od razu jako generowanie pustego pliku. Jednak tutaj ponownie :można to łatwo przeoczyć i / lub uznać za monit.
  • true > file: co ma wartość logiczna w przypadku przekierowania lub zawartości pliku? Co tu mamy na myśli? to pierwsza rzecz, jaka przychodzi mi do głowy, kiedy to czytam.
  • cat /dev/null > file. Łączy się /dev/nullw file? catsą często postrzegane jako polecenia zrzucić zawartość pliku, który może jeszcze sens: zrzucić zawartość do pliku w pustymfile , trochę jak pokrętny sposób powiedzieć, cp /dev/null fileale nadal zrozumiałe.
  • cp /dev/null file. Kopiuje zawartość pustego pliku do file. Ma sens, jeśli ktoś nie wie, jak cpma zrobić domyślnie może pomyśleć, starasz się, aby filedo nullurządzenia, jak również.
  • eval > filelub eval '' > file. Nic nie uruchamia i przekierowuje dane wyjściowe do file. Dla mnie to ma sens. Dziwne, że to nie jest powszechny idiom.
  • printf '' > file: jawnie drukuje nic do pliku. Ten, który ma dla mnie największy sens.

Pod względem wydajności

Różnica polega na tym, czy używamy wbudowanej powłoki, czy nie. Jeśli nie, należy rozwidlić proces, załadować i wykonać polecenie.

evalgwarantuje się, że będzie wbudowany we wszystkie powłoki. :jest wbudowany tam, gdzie jest dostępny (lubi Bourne / csh). truejest wbudowany tylko w powłoki podobne do Bourne'a.

printfjest wbudowany w najbardziej nowoczesne powłoki podobne do Bourne'a i fish.

cpi catgeneralnie nie są wbudowane.

Teraz cp /dev/null filenie wywołuje przekierowań powłoki, więc rzeczy takie jak:

find . -exec cp /dev/null {} \;

będą bardziej wydajne niż:

find . -exec sh -c '> "$1"' sh {} \;

(choć niekoniecznie niż:

find . -exec sh -c 'for f do : > "$f"; done' sh {} +

).

Osobiście

Osobiście używam : > filew powłokach podobnych do Bourne'a i obecnie nie używam niczego innego niż powłoki podobne do Bourne'a.

Stéphane Chazelas
źródło
Co dd of=file count=0?
kojiro
2
@kojiro, w przypadku niektórych implementacji dd(takich jak przynajmniej Solaris 10), count=0jest ignorowany. dd if=/dev/null of=filebyłby bardziej przenośny. W każdym razie jest to niezależne od powłoki.
Stéphane Chazelas
OK, ale nie mniej zasługuje na włączenie niż cp /dev/null file, prawda?
kojiro
2
@kojiro, cp /dev/null filejest powszechnym idiomem. Ograniczam się do tych, nie chodzi o to, żeby wymienić wszystkie możliwe sposoby.
Stéphane Chazelas
5

Możesz spojrzeć na to truncate, co robi dokładnie to: obciąć plik.

Na przykład:

truncate --size 0 file.txt

Jest to prawdopodobnie wolniejsze niż używanie true > file.txt.

Jednak moim głównym celem jest: truncatejest przeznaczone do obcinania plików, podczas gdy używanie> ma efekt uboczny obcinania pliku.

fabiański
źródło
2
Obcinanie jest przydatne, gdy chcesz obciąć plik do czegoś innego niż 0. To powiedziawszy, nawet bez powłoki jest dziwne stwierdzenie: czy możesz opisać kontekst, w którym truncatebyłby dostępny, ale >ani unistdbiblioteki C nie byłyby dostępne?
kojiro
Nie całkiem. Prawdopodobnie istnieje bardziej eleganckie rozwiązanie dla każdego dostępnego języka skryptowego lub programowania.
Fabian
3
truncatejest narzędziem FreeBSD, stosunkowo niedawno (2008) dodanym do jądra GNU (choć --sizedługi styl opcji GNU jest specyficzny dla GNU), więc nie jest dostępny w systemach innych niż GNU lub FreeBSD i nie jest dostępny w starszych systemach GNU, Nie powiedziałbym, że jest przenośny. cp /dev/null filedziałałby bez przekierowania powłoki i byłby bardziej przenośny.
Stéphane Chazelas
Okej, usunę ten komentarz dotyczący przenośności. Chociaż twoja ostatnia definicja wydaje się być inna.
Fabian
2

Odpowiedź zależy trochę od tego file.txt, co jest i od tego , jak proces do tego napisze!

Przytoczę typowy przypadek użycia: masz rosnący plik dziennika o nazwie file.txti chcesz go obrócić.

Dlatego kopiujesz na przykład file.txtdo file.txt.save, a następnie obcinasz file.txt.

W tym scenariuszu, JEŻELI plik nie zostanie otwarty przez another_process(np. another_processProgram może wyświetlać dane w tym pliku, na przykład program rejestrujący coś), wówczas dwie propozycje są równoważne i obie działają dobrze (ale druga jest preferowana jako pierwszy „cat / dev / null> file.txt” to Bezużyteczne użycie Cat, a także otwiera i czyta / dev / null).

Ale prawdziwym problemem byłoby, gdyby other_processnadal był aktywny i nadal miał otwarty uchwyt przechodzący do pliku.txt.

Następnie powstają 2 główne przypadki, w zależności od tego, jak other processplik został otwarty:

  • Jeśli other_processotworzy się w normalny sposób, uchwyt będzie nadal wskazywał poprzednią lokalizację w pliku, na przykład z przesunięciem 1200 bajtów. Następny zapis rozpocznie się zatem z przesunięciem 1200, a zatem znów będziesz mieć plik 1200 bajtów (+ cokolwiek napisał inny_proces), zawierający 1200 wiodących znaków zerowych! Zakładam, że nie to, czego chcesz .

  • Jeśli zostanie other_processotwarty file.txtw „trybie dołączania”, to za każdym razem, gdy pisze, wskaźnik aktywnie szuka końca pliku. Dlatego, kiedy go obetniesz, będzie „szukał” aż do bajtu 0 i nie będziesz miał złego efektu ubocznego! Tego właśnie chcesz (... zwykle!)

Pamiętaj, że oznacza to, że po przycięciu pliku musisz upewnić się, że wszystkie osoby other_processnadal zapisujące w tej lokalizacji otworzyły go w trybie „dołącz”. W przeciwnym razie musisz je zatrzymać other_processi uruchomić ponownie, aby zaczęły wskazywać początek pliku zamiast poprzedniej lokalizacji.

Odniesienia: /programming//a/16720582/1841533 w celu uzyskania bardziej przejrzystych wyjaśnień oraz miły krótki przykład różnicy między rejestrowaniem w trybie normalnym a dołączaniem w /programming//a/984761/1841533

Olivier Dulac
źródło
2
Bardzo niewiele z tej odpowiedzi w rzeczywistości dotyczy pytania lub odpowiada na nie. Różnica między a cat /dev/null > filea > fileto cat /dev/nulla, która nie ma znaczenia dla pliku.
jw013
@ jw013: Prawda! Chciałem jednak skorzystać z okazji, by ponownie podać informację „czego chcesz / czego nie chcesz”, ponieważ nie jest ona zbyt dobrze znana i może mocno uderzyć kogoś, kto próbuje obrócić dzienniki (częsty przypadek, w którym chcesz obciąć plik).
Olivier Dulac
1
Na wszystko jest czas i miejsce. Twoje informacje mogą być przydatne w innym kontekście, ale tutaj nie należą - powinieneś znaleźć bardziej odpowiednie miejsce, ponieważ nikt nie próbuje obracać logów, nie zajrzy do tego całkowicie niezwiązanego pytania o przekierowanie. Tutaj twoja odpowiedź jest odpowiednikiem cyfrowego chwastu, podobnie jak inaczej przydatna roślina dyniowa na środku pola kukurydzy byłaby uważana za chwast.
jw013
1

Lubię to i używam go często, ponieważ wygląda na czystszego, a nie tak, jakby ktoś przypadkowo nacisnął klawisz powrotu:

echo -n "" > file.txt

Powinien też być wbudowany?

awsm
źródło
3
Istnieje wiele sposobów zerowania pliku. Myślę, że KM. był zainteresowany jedynie zrozumieniem różnicy między dwiema metodami przedstawionymi w pytaniu.
drs
6
Wiele echowdrożeń nie obsługuje -n(i dane wyjściowe -n<SPC><NL>tutaj. printf '' > file.txtByłyby bardziej przenośne (przynajmniej w nowoczesnych systemach / POSIX).
Stéphane Chazelas