Mam pliki, które kończą się na jednej lub więcej linii i powinny kończyć się tylko na jednej linii. Jak mogę to zrobić za pomocą narzędzi Bash / Unix / GNU?
Przykład nieprawidłowego pliku:
1\n
\n
2\n
\n
\n
3\n
\n
\n
\n
Przykład poprawionego pliku:
1\n
\n
2\n
\n
\n
3\n
Innymi słowy: powinna istnieć dokładnie jedna nowa linia między EOF a ostatnim nie-nowym znakiem pliku.
Wdrożenie referencyjne
Odczytaj zawartość pliku, odetnij jedną nową linię, aż na końcu nie będą już więcej dwóch nowych linii, zapisz ją ponownie:
#! /bin/python
import sys
with open(sys.argv[1]) as infile:
lines = infile.read()
while lines.endswith("\n\n"):
lines = lines[:-1]
with open(sys.argv[2], 'w') as outfile:
for line in lines:
outfile.write(line)
Wyjaśnienie: Oczywiście, orurowanie jest dozwolone, jeśli jest to bardziej eleganckie.
sed
propozycję, pomyślałem po prostu OMG ...awk: illegal statement
.brew install mawk
i zmieniając polecenie namawk
działające.Od przydatnych skryptów jednowierszowych dla sed .
źródło
find . -type f -name '*.js' -exec sed --in-place -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
find . -type f -name '*.js' -exec sed -i '' -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
Ponieważ masz już odpowiedzi za pomocą bardziej odpowiednich narzędzi sed i awk; możesz skorzystać z faktu, że
$(< file)
usuwa on końcowe puste linie.Ten tani hack nie działałby w celu usunięcia końcowych pustych linii, które mogą zawierać spacje lub inne znaki niedrukowalne, a jedynie w celu usunięcia końcowych pustych linii. Nie zadziała również, jeśli plik zawiera null bajty.
W powłokach innych niż bash i zsh użyj
$(cat file)
zamiast$(<file)
.źródło
$()
odrzuca końcowe znaki nowej linii. To decyzja projektowa. Zakładam, że ułatwi to integrację z innymi łańcuchami:echo "On $(date ...) we will meet."
byłoby złe z nową linią, którą wypuszcza prawie każde polecenie powłoki na końcu.[[ $a == '' ]] || printf '%s\n' "$a" >"$file"
.a=$(gtac file.txt); printf '%s\n' "$a" | gtac > file.txt
Możesz użyć tej sztuczki z
cat
&printf
:Na przykład
$
Oznacza końca linii.Referencje
źródło
To pytanie jest oznaczone jako ed , ale nikt nie zaproponował
ed
rozwiązania.Tutaj jest jeden:
lub równoważnie
ed
po uruchomieniu domyślnie umieści cię w ostatnim wierszu bufora edycji.Pierwsze polecenie (
a
) dodaje pustą linię na końcu bufora (pusta linia w skrypcie edycyjnym to ta linia, a kropka (.
) służy tylko do powrotu do trybu komend).Drugie polecenie (
?
) wyszukuje najbliższy poprzedni wiersz, który zawiera coś (nawet znaki spacji), a następnie usuwa wszystko do końca bufora od następnego wiersza.Trzecie polecenie (
w
) zapisuje plik z powrotem na dysk.Dodana pusta linia chroni resztę pliku przed usunięciem w przypadku, gdy na końcu oryginalnego pliku nie ma żadnych pustych linii.
źródło
Oto rozwiązanie Perla, które nie wymaga odczytywania więcej niż jednej linii do pamięci na raz:
lub jako jedna linijka:
To czyta plik po linii na raz i sprawdza każdą linię, aby sprawdzić, czy zawiera znak inny niż nowy wiersz. Jeśli nie, zwiększa licznik; jeśli tak, drukuje liczbę nowych linii wskazanych przez licznik, a następnie samą linię, a następnie resetuje licznik.
Technicznie, nawet buforowanie pojedynczej linii w pamięci nie jest konieczne; możliwe byłoby rozwiązanie tego problemu przy użyciu stałej ilości pamięci przez odczytanie pliku we fragmentach o stałej długości i przetworzenie go znak po znaku za pomocą automatu stanów. Podejrzewam jednak, że byłoby to niepotrzebnie skomplikowane w typowym przypadku użycia.
źródło
Jeśli twój plik jest wystarczająco mały, aby zmieścić się w pamięci, możesz go użyć
źródło
W Pythonie (wiem, że nie jest to, czego chcesz, ale jest o wiele lepsze, ponieważ jest zoptymalizowany i stanowi preludium do wersji bash) bez przepisywania pliku i bez czytania całego pliku (co jest dobre, jeśli plik jest bardzo duży):
Zauważ, że nie działa na plikach, w których znak EOL nie jest „\ n”.
źródło
Wersja bashowa, implementująca algorytm pythonowy, ale mniej wydajna, ponieważ wymaga wielu procesów:
źródło
Ten jest szybki do pisania, a jeśli znasz sed, łatwy do zapamiętania:
Używa skryptu sed, aby usunąć wiodące puste wiersze z przydatnych skryptów jednowierszowych dla sed , do których odwołują się Alexey, powyżej i tac (reverse cat).
W szybkim teście na pliku o wielkości 18 MB i 64 000 linii podejście Aleksieja było szybsze (0,036 vs 0,046 sekundy).
źródło