Mam kilka plików, z których chciałbym usunąć ostatni znak nowej linii, jeśli jest to ostatni znak w pliku. od -c
pokazuje mi, że polecenie, które wykonuję, zapisuje plik z końcową nową linią:
0013600 n t > \n
Wypróbowałem kilka sztuczek z sedem, ale najlepsze, o czym przyszło mi do głowy, nie działa:
sed -e '$s/\(.*\)\n$/\1/' abc
Jakieś pomysły, jak to zrobić?
\n
, w linuksie jest jedna postaćOdpowiedzi:
lub, aby edytować plik w miejscu:
[Od redakcji:
-pi -e
było pierwotnie-pie
, ale, jak zauważyło kilku komentatorów i wyjaśniło @hvd, to drugie nie działa.]Na stronie awk, którą widziałem, zostało to opisane jako „bluźnierstwo perla”.
Ale w teście zadziałało.
źródło
chomp
. I to jest lepsze niż siorbanie pliku.perl -pi -e 'chomp if eof' filename
, do edycji pliku na miejscu zamiast tworzenia pliku tymczasowegoperl -pie 'chomp if eof' filename
-> Nie można otworzyć skryptu perla "chomp if eof": Brak takiego pliku lub katalogu;perl -pi -e 'chomp if eof' filename
-> działaMożesz wykorzystać fakt, że podstawienia poleceń powłoki usuwają końcowe znaki nowej linii :
Prosta forma, która działa w bash, ksh, zsh:
Przenośna (zgodna z POSIX) alternatywa (nieco mniej wydajna):
Uwaga:
in.txt
kończy się wieloma znakami nowej linii, podstawienie polecenia usuwa je wszystkie - dzięki, @Sparhawk. (Nie usuwa białych znaków innych niż końcowe znaki nowej linii).printf %s
zapewnia, że do danych wyjściowych nie zostanie dołączony znak nowej linii (jest to zgodna z POSIX alternatywa dla niestandardowegoecho -n
; patrz http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html i https: //unix.stackexchange. pl / a / 65819 )Podręcznik do innych odpowiedzi :
Jeśli Perl jest dostępny, wybierz zaakceptowaną odpowiedź - jest prosta i wydajna w pamięci (nie czyta od razu całego pliku wejściowego).
W przeciwnym razie rozważ odpowiedź Awk ghostdog74 - jest niejasna, ale także wydajna pod względem pamięci ; równoważne bardziej czytelne (POSIX) stanowi:
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
bloku, gdzie jest drukowana bez\n
końca z powodu ustawienia separatora rekordów wyjściowych (OFS
) na pusty łańcuch.Jeśli chcesz uzyskać szczegółowe, ale szybkie i niezawodne rozwiązanie, które naprawdę edytuje w miejscu (w przeciwieństwie do tworzenia pliku tymczasowego, który następnie zastępuje oryginał), rozważ skrypt Perl jrockway .
źródło
Możesz to zrobić z
head
GNU coreutils, obsługuje argumenty, które są względne do końca pliku. Aby więc zostawić ostatnie użycie bajtu:Aby przetestować końcową linię nowej linii, możesz użyć
tail
iwc
. Poniższy przykład zapisuje wynik w pliku tymczasowym, a następnie zastępuje oryginał:Możesz również użyć
sponge
from,moreutils
aby przeprowadzić edycję „lokalną”:Możesz również utworzyć ogólną funkcję wielokrotnego użytku, umieszczając ją w swoim
.bashrc
pliku:Aktualizacja
Jak zauważył KarlWilbur w komentarzach i użyty w odpowiedzi Sorentara ,
truncate --size=-1
może zastępowaćhead -c-1
i wspierać edycję w miejscu.źródło
truncate --size=-1
zamiast tego,head -c -1
ponieważ po prostu zmienia rozmiar pliku wejściowego, zamiast czytać plik wejściowy, zapisując go do innego pliku, a następnie zastępując oryginał plikiem wyjściowym.head -c -1
usunie ostatni znak, niezależnie od tego, czy jest to nowa linia, czy nie, dlatego musisz sprawdzić, czy ostatni znak jest nową linią, zanim go usuniesz.Edycja 2:Otoawk
wersja (poprawiona) , która nie gromadzi potencjalnie ogromnej tablicy:awk '{if (line) print line; line = $ 0} END {printf $ 0} 'abcźródło
awk
wersję. Bierze dwa przesunięcia (i inny test), a ja użyłem tylko jednego. Możesz jednak użyćprintf
zamiastORS
.head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
gapić się
źródło
awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file
powinno być łatwiejsze do odczytania.awk 'NR>1 {print p} {p=$0} END {printf $0}' file
.printf
to argument formatu . Tak więc, jeśli plik wejściowy zawiera coś, co można zinterpretować jako specyfikator formatu, na przykład%d
, pojawi się błąd. Rozwiązaniem byłoby zmienić to naprintf "%s" $0
Bardzo prosta metoda dla plików jednowierszowych, wymagająca echa GNU z coreutils:
źródło
\n
jest obecny. Gdy zostanie przekonwertowany na nową linię.$(...)
cytuję/bin/echo -n "$(cat infile)"
Poza tym nie jestem pewien, jakaecho
byłaby maksymalna długość lub powłoka w wersjach systemu operacyjnego / powłoki / dystrybucji (właśnie to szukałem w Google i była to królicza nora), więc jestem Nie jestem pewien, jak przenośny (lub wydajny) byłby w rzeczywistości dla czegokolwiek innego niż małe pliki - ale dla małych plików, świetnie.Jeśli chcesz to zrobić dobrze, potrzebujesz czegoś takiego:
Otwieramy plik do odczytu i dołączenia; otwarcie do dołączenia oznacza, że jesteśmy już
seek
na końcu pliku. Następnie otrzymujemy numeryczną pozycję końca pliku za pomocątell
. Używamy tej liczby do wyszukiwania wstecz jednego znaku, a następnie czytamy ten jeden znak. Jeśli jest to znak nowej linii, skracamy plik do znaku przed tą linią, w przeciwnym razie nic nie robimy.Działa to w stałym czasie i stałej przestrzeni dla dowolnego wejścia i nie wymaga też więcej miejsca na dysku.
źródło
Oto ładne, uporządkowane rozwiązanie w języku Python. Nie próbowałem tu być lakoniczny.
To modyfikuje plik na miejscu, zamiast tworzyć kopię pliku i usuwać znak nowej linii z ostatniego wiersza kopii. Jeśli plik jest duży, będzie to znacznie szybsze niż rozwiązanie Perla, które zostało wybrane jako najlepsza odpowiedź.
Obcina plik o dwa bajty, jeśli ostatnie dwa bajty to CR / LF, lub o jeden bajt, jeśli ostatni bajt to LF. Nie podejmuje próby modyfikacji pliku, jeśli ostatnie bajty nie są (CR) LF. Obsługuje błędy. Przetestowano w Pythonie 2.6.
Umieść to w pliku o nazwie „striplast” i
chmod +x striplast
.PS W duchu „Perl golfa”, oto moje najkrótsze rozwiązanie w Pythonie. Siorbi cały plik ze standardowego wejścia do pamięci, usuwa wszystkie znaki nowej linii z końca i zapisuje wynik na standardowe wyjście. Nie tak zwięzły jak Perl; po prostu nie możesz pokonać Perla w takich drobnych, szybkich rzeczach.
Usuń znak „\ n” z wywołania do
.rstrip()
i usunie cały biały znak na końcu pliku, w tym wiele pustych wierszy.Umieść to w „slurp_and_chomp.py” i uruchom
python slurp_and_chomp.py < inputfile > outputfile
.źródło
Szybkim rozwiązaniem jest użycie narzędzia gnu
truncate
:Test będzie prawdziwy, jeśli plik ma na końcu nową linię.
Usuwanie jest bardzo szybkie, naprawdę na miejscu, nie jest potrzebny nowy plik, a wyszukiwanie również odczytuje od końca tylko jeden bajt (
tail -c1
).źródło
[ -z $(tail -c1 filename) ] && truncate -s -1 filename
(również w odpowiedzi na inny komentarztruncate
polecenie nie działa ze standardowym wejściem, wymagana jest nazwa pliku)Jeszcze inny perl WTDI:
źródło
Zobacz także Dopasuj dowolny znak (w tym znaki nowej linii) w sed .
źródło
tr -d '\n'
Korzystanie z dd:
źródło
źródło
g
lub nawiasów wokółeof
:perl -pi -e 's/\n$// if eof' your_file
.Zakładając typ pliku Unix i chcesz, aby tylko ostatnia nowa linia działała.
Nie będzie działać na wielu nowych liniach ...
* Działa tylko wtedy, gdy ostatnia linia jest pusta.
źródło
sed
rozwiązanie, które działa nawet w przypadku niepustego ostatniego wiersza: stackoverflow.com/a/52047796Jeszcze inna odpowiedź FTR (i moja ulubiona!): Echo / cat to, co chcesz rozebrać i przechwycić dane wyjściowe za pomocą backticks. Ostatnia nowa linia zostanie usunięta. Na przykład:
źródło
POSIX SED:
„$ {/ ^ $ / d}”
źródło
echo -en 'a\nb\n' | sed '${/^$/d}'
niczego nie usunie.echo -en 'a\nb\n\n' | sed '${/^$/d}'
zostanie usunięty, ponieważ cała ostatnia linia jest pusta.Jest to dobre rozwiązanie, jeśli chcesz, aby działało z potokami / przekierowaniami zamiast odczytywania / wyprowadzania z lub do pliku. Działa to z jedną lub wieloma liniami. Działa niezależnie od tego, czy jest końcowy znak nowej linii, czy nie.
Detale:
head -c -1
obcina ostatni znak ciągu, niezależnie od tego, jaki to znak. Więc jeśli ciąg nie kończy się znakiem nowej linii, tracisz znak.sed '$s/$//'
. Pierwszy$
oznacza zastosowanie polecenia tylko do ostatniej linii.s/$//
oznacza zastąpienie „końca wiersza” słowem „nic”, co oznacza nic nie robienie. Ale ma to efekt uboczny dodania końcowego znaku nowej linii, jeśli go nie ma.Uwaga: domyślnie Mac
head
nie obsługuje tej-c
opcji. Możesz to zrobićbrew install coreutils
i użyćghead
zamiast tego.źródło
Chciałem to zrobić tylko dla kodu golfa, a potem po prostu skopiowałem kod z pliku i wkleiłem go do
echo -n 'content'>file
instrukcji.źródło
źródło
Miałem podobny problem, ale pracowałem z plikiem Windows i muszę zachować te CRLF - moje rozwiązanie w systemie Linux:
źródło
Powinno usunąć ostatnie wystąpienie \ nw pliku. Nie działa na dużym pliku (z powodu ograniczenia bufora seda)
źródło
rubin:
lub:
źródło