Mam plik foo.txt
zawierający następujące wiersze:
a
b
c
Chcę prostego polecenia, które powoduje zawartość foo.txt
:
a
b
Mam plik foo.txt
zawierający następujące wiersze:
a
b
c
Chcę prostego polecenia, które powoduje zawartość foo.txt
:
a
b
Odpowiedzi:
Używanie GNU sed
:
sed -i '$ d' foo.txt
-i
Opcja nie istnieje w GNU sed
wersjach starszych niż 3,95, więc trzeba używać go jako filtr z pliku tymczasowego:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
Oczywiście w takim przypadku możesz również użyć head -n -1
zamiast sed
.
System operacyjny Mac:
W systemie Mac OS X (od 10.7.4) odpowiednikiem sed -i
powyższego polecenia jest
sed -i '' -e '$ d' foo.txt
$ d
wyrażeniem regularnym. To rozkaz sed. d
to polecenie służące do usunięcia wiersza, natomiast $
oznacza „ostatni wiersz w pliku”. Podczas określania lokalizacji (zwanej „zasięgiem” w sed lingo) przed poleceniem, polecenie to jest stosowane tylko do określonej lokalizacji. Zatem to polecenie wyraźnie mówi „w zakresie ostatniego wiersza w pliku, usuń go”. Całkiem sprytnie i od razu do rzeczy, jeśli mnie pytasz.
Jest to zdecydowanie najszybsze i najprostsze rozwiązanie, szczególnie w przypadku dużych plików:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
jeśli chcesz usunąć górny wiersz, użyj tego:
tail -n +2 foo.txt
co oznacza linie wyjściowe zaczynające się od linii 2.
Nie używaj sed
do usuwania linii z góry lub z dołu pliku - jest bardzo bardzo wolny, jeśli plik jest duży.
head -n -1 foo.txt
wystarczy
brew install coreutils
(narzędzia GNU core) i używać ghead
zamiast head
.
FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}
Uruchom go, aby usunąć 4 linie, na przykład z ./TAILfixer myfile 4
chmod +x TAILfixer
sed
, to polecenie jest również do cholery powolne
Miałem problem ze wszystkimi odpowiedziami tutaj, ponieważ pracowałem z OGROMNYM plikiem (~ 300 Gb) i żadne z rozwiązań nie skalowało się. Oto moje rozwiązanie:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
Innymi słowy: znajdź długość pliku, z którym chcesz skończyć (długość pliku minus długość długości ostatniego wiersza, używając bc
) i ustaw tę pozycję na koniec pliku (wprowadzając dd
jeden bajt /dev/null
na to).
Jest to szybkie, ponieważ tail
zaczyna czytać od końca i dd
zastąpi plik na miejscu, zamiast kopiować (i analizować) każdą linię pliku, co robią inne rozwiązania.
UWAGA: To usuwa linię z pliku na miejscu! Utwórz kopię zapasową lub przetestuj plik zastępczy przed wypróbowaniem go na własnym pliku!
Aby usunąć ostatnią linię z pliku bez czytania całego pliku lub przepisywania czegokolwiek , możesz użyć
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
Aby usunąć ostatni wiersz i wydrukować go na standardowym wyjściu („pop”), możesz połączyć to polecenie z tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
Te polecenia mogą skutecznie przetwarzać bardzo duży plik. Jest to podobne i inspirowane odpowiedzią Yossi, ale unika korzystania z kilku dodatkowych funkcji.
Jeśli zamierzasz używać ich wielokrotnie i chcesz obsługiwać błędy oraz niektóre inne funkcje, możesz użyć poptail
polecenia tutaj:
https://github.com/donm/evenmoreutils
truncate
domyślnie nie jest dostępna w systemie OS X. Ale to jest łatwe do zainstalowania za pomocą Brew: brew install truncate
.
Użytkownicy komputerów Mac
jeśli chcesz tylko usunąć wyjście z ostatniego wiersza bez zmiany samego pliku, wykonaj
sed -e '$ d' foo.txt
jeśli chcesz usunąć ostatni wiersz samego pliku wejściowego, zrób to
sed -i '' -e '$ d' foo.txt
-i ''
mówi sedowi, aby zmodyfikował plik w miejscu, zachowując kopię zapasową w pliku z rozszerzeniem podanym jako parametr. Ponieważ parametr jest pustym ciągiem, plik kopii zapasowej nie jest tworzony. -e
każe sedowi wykonać polecenie. Polecenie $ d
oznacza: znajdź ostatni wiersz ( $
) i usuń go ( d
).
Na Macu, head -n -1 nie będzie działać. I próbowałem znaleźć proste rozwiązanie (nie martwiąc się czasem przetwarzania), aby rozwiązać ten problem tylko za pomocą poleceń „głowa” i / lub „ogon”.
Wypróbowałem następującą sekwencję poleceń i cieszę się, że mogłem ją rozwiązać za pomocą polecenia „tail” [z opcjami dostępnymi na Macu]. Tak więc, jeśli jesteś na komputerze Mac i chcesz użyć tylko „ogona”, aby rozwiązać ten problem, możesz użyć tego polecenia:
plik cat.txt | ogon -r | ogon -n +2 | ogon -r
1> tail -r: po prostu odwraca kolejność linii na wejściu
2> tail -n +2: drukuje wszystkie linie zaczynające się od drugiej linii na wejściu
ghead -n -1
awk 'NR>1{print buf}{buf = $0}'
Zasadniczo ten kod mówi:
Dla każdej linii po pierwszej wydrukuj buforowaną linię
dla każdej linii zresetuj bufor
Bufor jest opóźniony o jedną linię, stąd kończy się drukowanie linii od 1 do n-1
awk "NR != `wc -l < text.file`" text.file |> text.file
Ten fragment kodu załatwia sprawę.
Oba te rozwiązania są tutaj w innych formach. Uważam, że są one trochę bardziej praktyczne, jasne i przydatne:
Za pomocą dd:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}
Za pomocą obcięcia:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
Oto, jak możesz to zrobić ręcznie (osobiście często używam tej metody, gdy muszę szybko usunąć ostatnią linię w pliku):
vim + [FILE]
Ten +
znak oznacza, że gdy plik zostanie otwarty w edytorze tekstów vim, kursor zostanie umieszczony w ostatnim wierszu pliku.
Teraz naciśnij d
dwa razy na klawiaturze. To zrobi dokładnie to, co chcesz - usuń ostatni wiersz. Następnie naciśnij, :
a x
następnie naciśnij Enter
. Spowoduje to zapisanie zmian i powrót do powłoki. Teraz ostatni wiersz został pomyślnie usunięty.
sed -i
powyższego polecenia jestsed -i '' -e '$ d' foo.txt
. Ponadtohead -n -1
obecnie nie działa na komputerze Mac.