2014-12-04 14 views
32

Say mam pewne arbitralne wielu linii pliku tekstowego:Jak mogę usunąć ostatni znak pliku w systemie UNIX?

sometext 
moretext 
lastline 

Jak mogę usunąć tylko ostatni znak (e, a nie nowej linii lub null) pliku bez dokonywania plik tekstowy nieważny?

+0

Co zrobiłeś, aby rozwiązać ten problem? -1 – Jotne

+2

Wymienienie garści śmieci i poleceń awk, które usuwają ostatnią postać z każdej linii, nie wydawały się strasznie konstruktywne. Heh, wiedziałem, że dostanę za to dinged. Mimo to nie mogłem zmusić się do odejścia w zdaniu "Próbowałem gromady sed i awk, ale mogłem jedynie rozebrać ostatni znak linii na różne sposoby". – MaxPRafferty

Odpowiedz

50

Prostsze podejście (wyjścia stdout, nie aktualizuje pliku wejściowego):

sed '$ s/.$//' somefile 
  • $ jest Sed adres, który pasuje tylko ostatnią linię wejściową, powodując następującą funkcję zadzwoń (s/.$//) do wykonania tylko w ostatnim wierszu.
  • s/.$// zamienia ostatni znak na (w tym przypadku ostatni) wiersz z pustym łańcuchem; tj. skutecznie usuwa ostatni znak. (przed newline) na linii.
    . dopasowuje dowolny znak na linii, a podążając za nim z $ zakotwicza dopasowanie do końca linii; zauważ, że użycie $ w tym wyrażeniu regularnym jest konceptualnie powiązane, ale technicznie odrębne od poprzedniego zastosowania $ jako adresu adresu.
  • przykład z wejściem standardowego wejścia (zakłada atakujących, KSH lub ZSH):

    $ sed '$ s/.$//' <<< $'line one\nline two' 
    line one 
    line tw 
    

Do zmiana pliku wejściowego zbyt (nie stosować, jeśli plik wejściowy jest symbolicznym):

sed -i '$ s/.$//' somefile 

Uwaga:
* na OSX, to że trzeba używać -i '' zamiast po prostu -i; omówienie pułapek związanych z -i, patrz dolna połowa my answer here.
* Jeśli potrzebujesz przetwarzać bardzo duże pliki wejściowe i/lub wydajność/użycie dysku są obawy i używasz narzędzi GNU (Linux), zobacz sorontar's helpful answer.

1

Po całą masę zabawy z różnych strategii (i unikanie sed -i lub Perl), najlepszym sposobem znalazłem to zrobić był z:

sed '$! { P; D; }; s/.$//' somefile 
+0

Nie wiem, dlaczego unikasz 'sed -i'. Jest to po prostu funkcja zapisu danych z powrotem do pliku. Teraz masz tylko wyjście do monitorowania. – Jotne

4

Oto kolejny używając ex, która mi się znaleźć nie tak tajemnicze jak sed rozwiązania:

printf '%s\n' '$' 's/.$//' wq | ex somefile 

$ idzie do ostatniej linii, s usuwa ostatni znak i wq jest dobrze znana (VI użytkownikach) Napisać + zamknąć.

1

EDYCJI ODPOWIEDŹ

stworzyłem skrypt i umieścić tekst wewnątrz na moim pulpicie. Test ten plik jest zapisywany jako „old_file.txt”

sometext 
moretext 
lastline 

Potem napisałem mały skrypt do podjęcia stary plik i eliminowania ostatni znak w ostatnim wierszu

#!/bin/bash 
no_of_new_line_characters=`wc '/root/Desktop/old_file.txt'|cut -d ' ' -f2` 
let "no_of_lines=no_of_new_line_characters+1" 
sed -n 1,"$no_of_new_line_characters"p '/root/Desktop/old_file.txt' > '/root/Desktop/my_new_file' 
sed -n "$no_of_lines","$no_of_lines"p '/root/Desktop/old_file.txt'|sed 's/.$//g' >> '/root/Desktop/my_new_file' 

otwarciu nowym_pliku stworzyłem wykazało wyjście następująco:

sometext 
moretext 
lastlin 

przepraszam za mojego poprzedniej odpowiedzi (nie czytając uważnie)

+1

Prosi o usunięcie tylko ostatniego znaku z pliku, a nie ostatniego znaku każdego wiersza. –

+1

Przepraszam za moją odpowiedź, nie czytałem uważnie .. Udało mi się uzyskać rozwiązanie za pomocą małego skryptu, który stworzyłem. Mam nadzieję, że to pomoże MaxPRafferty – repzero

1

Jeśli celem jest, aby usunąć ostatni znak w ostatnim wierszu, to awk powinien zrobić:

awk '{a[NR]=$0} END {for (i=1;i<NR;i++) print a[i];sub(/.$/,"",a[NR]);print a[NR]}' file 
sometext 
moretext 
lastlin 

przechowywać wszystkie dane do tablicy, a następnie wydrukować go i zmienić ostatni wiersz.

1

sed 's/.$//' filename | tee newFilename

Ten powinien wykonywać swoją pracę.

+1

To usunie ostatni znak z każdej linii, a nie tylko ostatni znak z ostatniej linii. – MaxPRafferty

+0

@MaxPRafferty my bad. Myślałem, że pytanie brzmi: usunąć ostatnią postać każdej linii. – karthik339

13

truncate

truncate -s-1 file 

usuwa jeden znak (-1) z końcem tego pliku. Dokładnie jako >> zostanie dołączony do tego samego pliku.

Problem z tym podejściem polega na tym, że nie zachowuje on wstecznego znaku nowego wiersza, jeśli istnieje.

Roztwór:

if  [ -n "$(tail -c1 file)" ] # if the file has not a trailing new line. 
then 
     truncate -s-1 file   # remove one char as the question request. 
else 
     truncate -s-2 file   # remove the last two characters 
     echo "" >> file    # add the trailing new line back 
fi 

ten działa, ponieważ ogon wykonuje ostatni bajt (nie znaków).

Prawie bez czasu nie zajmuje nawet dużych plików.

Dlaczego nie sed

Problem z sed rozwiązania jak sed '$ s/.$//' file jest to, że czyta cały plik pierwszy (biorąc długo z dużych plików), to trzeba plik tymczasowy (o takim samym rozmiarze jako oryginał):

sed '$ s/.$//' file > tempfile 
rm file; mv tempfile file 

Następnie przenieś plik temp, aby zastąpić plik.

+0

Bardzo miło! Nie wiedziałem o ścięciu, dziękuję. – MaxPRafferty

+0

niedostępne w macos? – olegtaranenko

1

Tylko uwaga: sed tymczasowo usunie plik. Jeśli śledzisz plik, otrzymasz ostrzeżenie "Brak takiego pliku lub katalogu" do momentu ponownego wydania komendy tail.

Powiązane problemy