Mam wiele plików tekstowych w katalogu i chcę usunąć ostatnią linię każdego pliku w katalogu.
Jak mogę to zrobić?
text-processing
files
ThehalfarisedPheonix
źródło
źródło
Odpowiedzi:
Jeśli masz dostęp do
vim
, możesz użyć:źródło
Możesz użyć tego przyjemnego onelinera, jeśli masz GNU
sed
.Spowoduje to usunięcie ostatniego wiersza każdego nie ukrytego pliku w bieżącym katalogu. Przełącznik
-i
GNUsed
oznacza działanie w miejscu i'$ d'
nakazujesed
usunięcie ostatniego wiersza ($
co oznacza ostatnie id
oznacza usunięcie).źródło
-i
GNUizmu, więc jest to dyskusja, ale straciłbym swoją starą brodę, gdybym nie zauważył, że niektóre starsze wersjesed
nie pozwalają na umieszczanie białych znaków pomiędzy$
id
(lub, ogólnie między wzorcem a poleceniem).*(.)
do globowania dla zwykłych plików, nie wiem o innych powłokach.Wszystkie pozostałe odpowiedzi mają problemy, jeśli katalog zawiera coś innego niż zwykły plik lub plik ze spacjami / znakami nowej nazwy. Oto coś, co działa niezależnie:
find "$dir" -type f
: znajdź pliki w katalogu$dir
-type f
które są zwykłymi plikami;-exec
wykonaj polecenie dla każdego znalezionego plikused -i
: edytuj pliki na miejscu;'$d'
: usuń (d
) ostatnią ($
) linię.'+'
: każesed
findowi dodawać argumenty do (nieco bardziej wydajne niż uruchamianie polecenia dla każdego pliku osobno, dzięki @zwol).Jeśli nie chcesz schodzić do podkatalogów, możesz dodać argument
-maxdepth 1
dofind
.źródło
find
jest to bardziej efektywnie napisanefind $dir -type f -exec sed -i '$d' '{}' '+'
.)-print0
nie występuje w pełnym poleceniu, po co to wyjaśniać?-depth 0
nie działa (findutils 4.4.2), powinno być-maxdepth 1
.-exec
.Korzystanie z GNU
sed -i '$d'
oznacza odczytanie pełnego pliku i zrobienie jego kopii bez ostatniego wiersza, podczas gdy o wiele bardziej efektywne byłoby po prostu obcięcie pliku na miejscu (przynajmniej w przypadku dużych plików).Dzięki GNU
truncate
możesz:Jeśli pliki są stosunkowo małe, prawdopodobnie byłoby to mniej wydajne, ponieważ uruchamia kilka poleceń na plik.
Zauważ, że w przypadku plików, które zawierają dodatkowe bajty po ostatnim znaku nowej linii (po ostatnim wierszu) lub innymi słowy, jeśli mają nieograniczoną linię ostatniego wiersza , wówczas w zależności od
tail
implementacjitail -n 1
zwrócą tylko te dodatkowe bajty (jak GNUtail
), lub ostatnia (właściwie rozdzielona) linia i te dodatkowe bajty.źródło
|wc -c
wtail
rozmowie? (lub a${#length}
)${#length}
nie działałby, ponieważ zlicza znaki, a nie bajty i$(...)
usuwałby znak nowego wiersza, więc${#...}
byłby wyłączony o jeden, nawet gdyby wszystkie znaki były jednobajtowe.Bardziej przenośne podejście:
Nie sądzę, żeby to wymagało wyjaśnienia ... z wyjątkiem tego, że w tym przypadku
d
jest to samo,$d
ponieważed
domyślnie wybiera ostatnią linię.To nie będzie wyszukiwać rekurencyjnie i nie będzie przetwarzać ukrytych plików (inaczej dotfiles).
Jeśli chcesz je edytować, zobacz Jak dopasować * do ukrytych plików w katalogu
źródło
[[]]
na,[]
to będzie on w pełni zgodny z POSIX. ([[ ... ]]
to bashism.)[[
to nie jest bashism )Jednowarstwowy zgodny z POSIX dla wszystkich plików rozpoczynających się rekurencyjnie w bieżącym katalogu, w tym plików kropkowych:
Tylko dla
.txt
plików, nie rekurencyjnie:Zobacz także:
źródło