@cikatomo: oznacza edycję bezpośrednią - edytuje plik za pomocą tego, co wygenerujesz.
drewrockshard
4
ogon jest DUŻO WOLNY niż sed. ogon potrzebuje 13,5 sekundy, sed potrzebuje 0,85 sekundy. Mój plik ma ~ 1 mln linii, ~ 100 MB. MacBook Air 2013 z dyskiem SSD.
-n x: Wystarczy wydrukować ostatnie xlinie. tail -n 5dałoby ci 5 ostatnich linii danych wejściowych. +Rodzaju znakiem odwraca argument i dokonać tailwydruku cokolwiek ale pierwsze x-1linie. tail -n +1wypisałby cały plik, tail -n +2wszystko oprócz pierwszej linii itp.
GNU tailjest znacznie szybszy niż sed. tailjest również dostępny w BSD, a -n +2flaga jest spójna dla obu narzędzi. Sprawdź strony podręcznika FreeBSD lub OS X, aby uzyskać więcej.
Wersja BSD może być jednak znacznie wolniejsza niż sed. Zastanawiam się, jak im się to udało; tailpowinien po prostu czytać plik linia po linii, podczas gdy sedwykonuje dość złożone operacje obejmujące interpretację skryptu, stosowanie wyrażeń regularnych i tym podobne.
Uwaga: możesz ulec pokusie użycia
# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2"$FILE">"$FILE"
ale to da ci pusty plik . Powodem jest to, że przekierowanie ( >) następuje zanim tailzostanie wywołane przez powłokę:
Zgodnie z tym ss64.com/bash/tail.html typowy bufor domyślnie przyjmuje wartość 32k, gdy używa się BSD „tail” z -ropcją. Może gdzieś w systemie jest ustawiony bufor? A -nmoże 32-bitowy numer ze znakiem?
Yzmir Ramirez
41
@Eddie: user869097 powiedział, że nie działa, gdy pojedyncza linia ma 15 Mb lub więcej. Tak długo, jak linie są krótsze, tailbędzie działać dla dowolnego rozmiaru pliku.
Aaron Digulla
6
czy możesz wyjaśnić te argumenty?
Dreampuf,
17
@Dreampuf - ze strony podręcznika:-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Will Sheppard
11
Chciałem się zgodzić z @JonaChristopherSahnwaldt - ogon jest o wiele, znacznie wolniejszy niż wariant sed, o rząd wielkości. Testuję to na pliku 500 000 KB linii (nie więcej niż 50 znaków na linię). Jednak potem zdałem sobie sprawę, że korzystam z wersji tail (FreeBSD) tail (która domyślnie jest dostarczana z OS X). Kiedy przełączyłem się na ogon GNU, wywołanie ogona było 10 razy szybsze niż wywołanie sed (a także wywołanie sed GNU). AaronDigulla ma rację tutaj, jeśli używasz GNU.
Dan Nguyen,
179
Możesz użyć -i, aby zaktualizować plik bez użycia operatora „>”. Następujące polecenie usunie pierwszy wiersz z pliku i zapisze go w pliku.
Nie, to mniej więcej tak wydajne, jak chcesz. Możesz napisać program C, który mógłby wykonać zadanie nieco szybciej (mniej czasu uruchamiania i przetwarzania argumentów), ale prawdopodobnie będzie dążył do tej samej prędkości co sed, gdy pliki stają się duże (i zakładam, że są duże, jeśli zajmuje to minutę ).
Ale twoje pytanie cierpi z powodu tego samego problemu, co wielu innych, ponieważ z góry zakłada rozwiązanie. Jeśli chcesz nam szczegółowo powiedzieć, co chcesz zrobić, a następnie jak , możemy zaproponować lepszą opcję.
Na przykład, jeśli jest to plik A, który przetwarza inny program B, jednym rozwiązaniem byłoby nie usunięcie pierwszego wiersza, ale zmodyfikowanie programu B, aby przetwarzał go inaczej.
Powiedzmy, że wszystkie twoje programy dołączają się do tego pliku A, a program B odczytuje i przetwarza pierwszy wiersz przed jego usunięciem.
Możesz przeprojektować program B, aby nie próbował usunąć pierwszego wiersza, ale zachował trwałe (prawdopodobnie oparte na plikach) przesunięcie do pliku A, aby przy następnym uruchomieniu mógł szukać tego przesunięcia, przetworzyć linię tam i zaktualizuj przesunięcie.
Następnie, w spokojnym czasie (północ?), Mógłby wykonać specjalne przetwarzanie pliku A, aby usunąć wszystkie aktualnie przetwarzane linie i ustawić przesunięcie z powrotem na 0.
Z pewnością szybsze będzie otwieranie programu i wyszukiwanie pliku niż otwieranie i przepisywanie. Ta dyskusja zakłada oczywiście, że masz kontrolę nad programem B. Nie wiem, czy tak jest, ale mogą istnieć inne możliwe rozwiązania, jeśli przekażesz dodatkowe informacje.
Myślę, że PO próbuje osiągnąć to, co sprawiło, że znalazłem to pytanie. Mam 10 plików CSV z 500k linii w każdym. Każdy plik ma ten sam wiersz nagłówka co pierwszy wiersz. Jestem cat: łącząc te pliki w jeden plik, a następnie importując je do DB, pozwalając DB tworzyć nazwy kolumn z pierwszego wiersza. Oczywiście nie chcę powtarzania tej linii w pliku 2-10.
db
1
@db W takim przypadku awk FNR-1 *.csvjest prawdopodobnie szybszy.
jinawee
10
Państwo może edytować pliki w kolejności: wystarczy użyć Perl -iflagę tak:
perl -ni -e 'print unless $. == 1' filename.txt
Powoduje to, że pierwsza linia znika, tak jak pytasz. Perl będzie musiał przeczytać i skopiować cały plik, ale ustawia zapis danych wyjściowych pod nazwą oryginalnego pliku.
Jak powiedział Pax, prawdopodobnie nie będziesz szybciej niż to. Powodem jest to, że prawie nie ma systemów plików obsługujących obcinanie od początku pliku, więc będzie to noperacja O ( ), w której njest rozmiar pliku. Tym, co możesz zrobić znacznie szybciej, jest zastąpienie pierwszego wiersza tą samą liczbą bajtów (być może ze spacjami lub komentarzem), co może działać dla Ciebie w zależności od tego, co próbujesz zrobić (co przy okazji?).
Re „... prawie nie ma systemów plików obsługujących obcinanie ...” : to interesujące; prosimy o uwzględnienie nawiasów okrągłych określających taki system plików.
agc
1
@agc: teraz nie ma znaczenia, ale moja pierwsza praca w latach 70. dotyczyła Quadex, małego startupu (już go nie ma i nie ma związku z dwiema firmami, które używają teraz tej nazwy). Mieli system plików, który pozwalał dodawać lub usuwać na początku lub na końcu pliku, używany głównie do implementacji edycji w mniej niż 3 KB, umieszczając pliki nad oknem i pod oknem. Nie miał własnej nazwy, był tylko częścią QMOS, systemu operacyjnego Quadex Multiuser. („Multi” to zwykle 2-3 na LSI-11/02 z mniej niż 64 KB pamięci RAM i zwykle kilka dyskietek 8 "typu RX01 każdy po 250 KB.) :-)
spongejest rzeczywiście znacznie czystszy i bardziej niezawodny niż przyjęte rozwiązanie ( tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE")
Jealie,
1
Należy wyjaśnić, że „gąbka” wymaga zainstalowania pakietu „moreutils”.
FedFranzoni
To jedyne rozwiązanie, które działało dla mnie, aby zmienić plik systemowy (na obrazie dokera Debiana). Inne rozwiązania nie powiodły się z powodu błędu „Zajęte urządzenie lub zasób” podczas próby zapisu pliku.
FedFranzoni
Ale czy spongebuforuje cały plik w pamięci? To nie zadziała, jeśli będzie to setki GB.
OrangeDog,
@OrangeDog, tak długo, jak system plików może go przechowywać, spongebędzie go wchłaniał, ponieważ używa pliku / tmp jako kroku pośredniego, który jest następnie używany do zastąpienia oryginału.
agc
8
Jeżeli chcesz zmodyfikować plik w miejscu, zawsze można użyć oryginalnego edzamiast swojego s treaming następcy sed:
ed "$FILE"<<<$'1d\nwq\n'
edKomenda był oryginalny edytor tekstu UNIX, zanim nie było nawet terminale pełnoekranowe, stacje robocze znacznie mniej graficznych. exRedaktor, znany jako co używasz podczas wpisywania w okrężnicy szybki w vi, jest ex tendencję wersja ed, więc wiele z tej samej pracy poleceń. Chociaż edma być używany interaktywnie, można go również używać w trybie wsadowym, wysyłając do niego ciąg poleceń, co właśnie robi to rozwiązanie.
Sekwencja <<<$'1d\nwq\n'wykorzystuje wsparcie dla atakujących tutaj-strings ( <<<) i cytaty POSIX ( $'... ') do wejścia zasilającego do edpolecenia składające się z dwóch linii: 1d, która d eletes ustawiają 1 , a następniewq , co wagowo obrzędów plik z powrotem do dysk, a następnie q uits sesję edycji.
@ niglesiais Nie zgadzam się z „bezużytecznym użyciem kota”, ponieważ wyjaśnia, że to rozwiązanie jest odpowiednie w przypadku treści przesyłanych strumieniowo, a nie tylko plików.
Titou
5
Przydałby się do tego vim:
vim -u NONE +'1d'+'wq!'/tmp/test.txt
Powinno to być szybsze, ponieważ vim nie będzie czytał całego pliku podczas przetwarzania.
Może być konieczne zacytowanie, +wq!czy twoja powłoka jest bash. Prawdopodobnie nie, ponieważ nie !ma go na początku słowa, ale nawyk cytowania rzeczy jest prawdopodobnie dobry. (A jeśli dążysz do super-wydajności, nie przytaczając niepotrzebnie, nie potrzebujesz cytatów wokół 1djednego z nich.)
Mark Reed
vim nie trzeba czytać całego pliku. W rzeczywistości, jeśli plik jest większy niż pamięć, zgodnie z pytaniem w tym Q, vim odczytuje cały plik i zapisuje go (lub większość) do pliku tymczasowego, a po edycji zapisuje wszystko z powrotem (do pliku stałego). Nie wiem, jak według ciebie mogłoby to działać bez tego.
Składnia to także praca, ale tylko wygenerować dwa pliki wyjściowe zamiast trzech: csplit file /^.*$/1. Albo prościej: csplit file //1. Albo jeszcze prościej: csplit file 2.
Marco Roy
1
Ponieważ wygląda na to, że nie mogę przyspieszyć usuwania, myślę, że dobrym rozwiązaniem może być przetworzenie pliku w partiach takich jak ten:
While file1 not empty
file2 = head -n1000 file1
process file2
sed -i -e "1000d" file1
end
Wadą tego jest to, że jeśli program zostanie zabity w środku (lub jeśli jest tam trochę złego sql - powodując śmierć lub blokowanie części „procesu”), pojawią się wiersze, które są pomijane lub przetwarzane dwukrotnie .
Czy wykonanie ogona w wierszach N-1 i przekierowanie go do pliku, a następnie usunięcie starego pliku i zmiana nazwy nowego pliku na starą nazwę, wystarczy?
Gdybym robił to programowo, czytałbym plik i pamiętał przesunięcie pliku, po przeczytaniu każdej linii, więc mogłem wrócić do tej pozycji, aby odczytać plik z jedną linią mniejszą.
Pierwsze rozwiązanie jest zasadniczo identyczne z tym, co robi teraz Brent. Nie rozumiem twojego podejścia programowego, tylko pierwszy wiersz musi zostać usunięty, wystarczy przeczytać i odrzucić pierwszy wiersz i skopiować resztę do innego pliku, który jest znowu taki sam jak podejście sed i tail.
Robert Gamble,
Drugie rozwiązanie sugeruje, że plik nie jest za każdym razem zmniejszany o pierwszą linię. Program po prostu przetwarza go, jakby został zmniejszony, ale za każdym razem zaczyna od następnego wiersza
EvilTeach
Nadal nie rozumiem, jakie jest twoje drugie rozwiązanie.
Odpowiedzi:
Spróbuj ogona :
-n x
: Wystarczy wydrukować ostatniex
linie.tail -n 5
dałoby ci 5 ostatnich linii danych wejściowych.+
Rodzaju znakiem odwraca argument i dokonaćtail
wydruku cokolwiek ale pierwszex-1
linie.tail -n +1
wypisałby cały plik,tail -n +2
wszystko oprócz pierwszej linii itp.GNU
tail
jest znacznie szybszy niżsed
.tail
jest również dostępny w BSD, a-n +2
flaga jest spójna dla obu narzędzi. Sprawdź strony podręcznika FreeBSD lub OS X, aby uzyskać więcej.Wersja BSD może być jednak znacznie wolniejsza niż
sed
. Zastanawiam się, jak im się to udało;tail
powinien po prostu czytać plik linia po linii, podczas gdysed
wykonuje dość złożone operacje obejmujące interpretację skryptu, stosowanie wyrażeń regularnych i tym podobne.Uwaga: możesz ulec pokusie użycia
ale to da ci pusty plik . Powodem jest to, że przekierowanie (
>
) następuje zanimtail
zostanie wywołane przez powłokę:$FILE
tail
tail
procesu na$FILE
tail
czyta z teraz pustego$FILE
Jeśli chcesz usunąć pierwszy wiersz w pliku, powinieneś użyć:
&&
Będzie upewnić się, że plik nie nadpisywane gdy pojawia się problem.źródło
-r
opcją. Może gdzieś w systemie jest ustawiony bufor? A-n
może 32-bitowy numer ze znakiem?tail
będzie działać dla dowolnego rozmiaru pliku.-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Możesz użyć -i, aby zaktualizować plik bez użycia operatora „>”. Następujące polecenie usunie pierwszy wiersz z pliku i zapisze go w pliku.
źródło
unterminated transform source string
sed -i '1,2d' filename
tail -n +2
. Nie jestem pewien, dlaczego nie jest to najlepsza odpowiedź.Dla tych, którzy korzystają z SunOS, który nie jest GNU, pomoże następujący kod:
źródło
Nie, to mniej więcej tak wydajne, jak chcesz. Możesz napisać program C, który mógłby wykonać zadanie nieco szybciej (mniej czasu uruchamiania i przetwarzania argumentów), ale prawdopodobnie będzie dążył do tej samej prędkości co sed, gdy pliki stają się duże (i zakładam, że są duże, jeśli zajmuje to minutę ).
Ale twoje pytanie cierpi z powodu tego samego problemu, co wielu innych, ponieważ z góry zakłada rozwiązanie. Jeśli chcesz nam szczegółowo powiedzieć, co chcesz zrobić, a następnie jak , możemy zaproponować lepszą opcję.
Na przykład, jeśli jest to plik A, który przetwarza inny program B, jednym rozwiązaniem byłoby nie usunięcie pierwszego wiersza, ale zmodyfikowanie programu B, aby przetwarzał go inaczej.
Powiedzmy, że wszystkie twoje programy dołączają się do tego pliku A, a program B odczytuje i przetwarza pierwszy wiersz przed jego usunięciem.
Możesz przeprojektować program B, aby nie próbował usunąć pierwszego wiersza, ale zachował trwałe (prawdopodobnie oparte na plikach) przesunięcie do pliku A, aby przy następnym uruchomieniu mógł szukać tego przesunięcia, przetworzyć linię tam i zaktualizuj przesunięcie.
Następnie, w spokojnym czasie (północ?), Mógłby wykonać specjalne przetwarzanie pliku A, aby usunąć wszystkie aktualnie przetwarzane linie i ustawić przesunięcie z powrotem na 0.
Z pewnością szybsze będzie otwieranie programu i wyszukiwanie pliku niż otwieranie i przepisywanie. Ta dyskusja zakłada oczywiście, że masz kontrolę nad programem B. Nie wiem, czy tak jest, ale mogą istnieć inne możliwe rozwiązania, jeśli przekażesz dodatkowe informacje.
źródło
awk FNR-1 *.csv
jest prawdopodobnie szybszy.Państwo może edytować pliki w kolejności: wystarczy użyć Perl
-i
flagę tak:Powoduje to, że pierwsza linia znika, tak jak pytasz. Perl będzie musiał przeczytać i skopiować cały plik, ale ustawia zapis danych wyjściowych pod nazwą oryginalnego pliku.
źródło
Możesz to łatwo zrobić za pomocą:
w wierszu poleceń; lub aby trwale usunąć pierwszą linię pliku, użyj trybu lokalnego z sed z
-i
flagą:źródło
Jak powiedział Pax, prawdopodobnie nie będziesz szybciej niż to. Powodem jest to, że prawie nie ma systemów plików obsługujących obcinanie od początku pliku, więc będzie to
n
operacja O ( ), w którejn
jest rozmiar pliku. Tym, co możesz zrobić znacznie szybciej, jest zastąpienie pierwszego wiersza tą samą liczbą bajtów (być może ze spacjami lub komentarzem), co może działać dla Ciebie w zależności od tego, co próbujesz zrobić (co przy okazji?).źródło
sponge
Util unika konieczności żonglowania pliku tymczasowego:źródło
sponge
jest rzeczywiście znacznie czystszy i bardziej niezawodny niż przyjęte rozwiązanie (tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)sponge
buforuje cały plik w pamięci? To nie zadziała, jeśli będzie to setki GB.sponge
będzie go wchłaniał, ponieważ używa pliku / tmp jako kroku pośredniego, który jest następnie używany do zastąpienia oryginału.Jeżeli chcesz zmodyfikować plik w miejscu, zawsze można użyć oryginalnego
ed
zamiast swojego s treaming następcysed
:ed
Komenda był oryginalny edytor tekstu UNIX, zanim nie było nawet terminale pełnoekranowe, stacje robocze znacznie mniej graficznych.ex
Redaktor, znany jako co używasz podczas wpisywania w okrężnicy szybki wvi
, jest ex tendencję wersjaed
, więc wiele z tej samej pracy poleceń. Chociażed
ma być używany interaktywnie, można go również używać w trybie wsadowym, wysyłając do niego ciąg poleceń, co właśnie robi to rozwiązanie.Sekwencja
<<<$'1d\nwq\n'
wykorzystuje wsparcie dla atakujących tutaj-strings (<<<
) i cytaty POSIX ($'
...'
) do wejścia zasilającego doed
polecenia składające się z dwóch linii:1d
, która d eletes ustawiają 1 , a następniewq
, co wagowo obrzędów plik z powrotem do dysk, a następnie q uits sesję edycji.źródło
powinien pokazywać linie oprócz pierwszej linii:
źródło
Przydałby się do tego vim:
Powinno to być szybsze, ponieważ vim nie będzie czytał całego pliku podczas przetwarzania.
źródło
+wq!
czy twoja powłoka jest bash. Prawdopodobnie nie, ponieważ nie!
ma go na początku słowa, ale nawyk cytowania rzeczy jest prawdopodobnie dobry. (A jeśli dążysz do super-wydajności, nie przytaczając niepotrzebnie, nie potrzebujesz cytatów wokół1d
jednego z nich.)Co powiesz na używanie csplit?
źródło
csplit file /^.*$/1
. Albo prościej:csplit file //1
. Albo jeszcze prościej:csplit file 2
.Ponieważ wygląda na to, że nie mogę przyspieszyć usuwania, myślę, że dobrym rozwiązaniem może być przetworzenie pliku w partiach takich jak ten:
Wadą tego jest to, że jeśli program zostanie zabity w środku (lub jeśli jest tam trochę złego sql - powodując śmierć lub blokowanie części „procesu”), pojawią się wiersze, które są pomijane lub przetwarzane dwukrotnie .
(plik1 zawiera wiersze kodu SQL)
źródło
Jeśli chcesz odzyskać po awarii, możesz po prostu skompilować plik z tym, co zrobiłeś do tej pory.
źródło
Ta jedna wkładka wykona:
Działa, ponieważ plik
tail
jest wykonywany przed,echo
a następnie plik jest odblokowany, dlatego nie jest potrzebny plik tymczasowy.źródło
Czy wykonanie ogona w wierszach N-1 i przekierowanie go do pliku, a następnie usunięcie starego pliku i zmiana nazwy nowego pliku na starą nazwę, wystarczy?
Gdybym robił to programowo, czytałbym plik i pamiętał przesunięcie pliku, po przeczytaniu każdej linii, więc mogłem wrócić do tej pozycji, aby odczytać plik z jedną linią mniejszą.
źródło