Jaki jest szybki i niezbyt skomplikowany sposób usunięcia wszystkich plików w katalogu o długości poniżej x linii, w bash?
Oto rozwiązanie POSIX, które powinno być łatwe do zrozumienia:
find . -type f -exec awk -v x=10 'NR==x{exit 1}' {} \; -exec echo rm -f {} \;
Jak w odpowiedzi Stephane'a , usuń, echo
kiedy będziesz zadowolony z tego, co zostanie usunięte.
Kropka .
oznacza bieżący katalog. find
znajduje pliki i katalogi rekurencyjnie wewnątrz .
i może z nimi robić różne rzeczy.
-type
jest jedną z find
„S barw podstawowych ; jest to test, który zostanie przeprowadzony dla każdego pliku i katalogu, który zostanie znaleziony rekurencyjnie (wewnątrz .
), a reszta liczb podstawowych w linii zostanie oceniona tylko wtedy, gdy da to wynik „prawda”.
W tym konkretnym przypadku kontynuujemy tylko wtedy, gdy mamy do czynienia ze zwykłym plikiem , a nie katalogiem lub czymś innym (np. Urządzeniem blokowym).
-exec
Podstawowej (z find
) wywołuje polecenie zewnętrzne, i przechodzi do następnego jedynie podstawowy jeśli polecenie zakończyło się pomyślnie zewnętrzny (stan wyjścia „0”). {}
Zostaje zastąpiona nazwą pliku jest „za” przez find
komendę. Pierwsze -exec
wywołanie jest więc równoważne z następującą komendą powłoki, wykonywaną kolejno dla każdego pliku:
awk -v x=10 'NR==x{exit 1}' ./somefilename
Awk to cały język sam w sobie, zaprojektowany do obsługi plików tekstowych z ogranicznikami, takich jak CSV. Warunki i polecenia Awk (zawarte między pojedynczymi cudzysłowami i rozpoczynające się od liter NR
) są wykonywane dla każdego wiersza pliku tekstowego. (Implicit looping.)
Aby w pełni nauczyć się Awk, bardzo polecam Samouczek Grymoire , ale wyjaśnię funkcje Awk użyte w powyższym poleceniu.
-v
Flagę Awk pozwala nam ustawić zmienną awk (raz) przed polecenia awk są wykonywane (dla każdej linii pliku). W tym przypadku mamy ustawiony x
na 10
.
NR
Jest to specjalna zmienna awk odnosi się do „ N umbra obecnego R ECORD”. Innymi słowy, jest to numer linii, na który patrzymy w konkretnym przejściu przez pętlę.
(Należy zauważyć, że jest możliwe, choć nietypowe, użycie innego „ separatora R ecord S ” niż domyślny znak nowej linii, poprzez ustawienie RS
. Oto przykład gry z separatorami rekordów. )
Skrypty Awk ogólnie składają się z warunków (poza nawiasami klamrowymi) połączonych z akcjami (wewnątrz nawiasów klamrowych). Mogą istnieć warunki złożone i akcje złożone, a także warunek domyślny (true) i akcja domyślna (print), ale potrzebujemy nie zawracaj sobie tym głowy.
Warunek tutaj jest: „Czy to jest linia 10-ci?” W takim przypadku wychodzimy z niezerowym statusem wyjścia, co w skrypcie powłoki oznacza „nieudane zakończenie polecenia”.
Dlatego jedynym sposobem na pomyślne zamknięcie tego polecenia Awk jest osiągnięcie końca pliku przed osiągnięciem 10. linii.
Więc jeśli skrypt Awk zakończy się pomyślnie, oznacza to, że masz plik krótszy niż dziesięć linii.
Następne -exec
wywołanie (jeśli usuniesz echo
) usunie każdy plik (który jest tak daleko w ocenie podstawowych find
), uruchamiając:
rm -f ./somefilename
Zakładając find
implementację, która obsługuje -readable
predykat (jeśli find
go nie obsługujesz, po prostu usuń go, otrzymasz tylko komunikaty o błędach dla plików nieczytelnych lub zamień na -exec test -r {} \;
):
x=10 find . -type f -readable -exec sh -c '
for file do
lines=$(wc -l < "$file") && [ "$((lines))" -lt "$x" ] && echo rm -f "$file"
done' sh {} +
Usuń echo
jeśli szczęśliwy.
To nie jest szczególnie skuteczny w tym, że zlicza wszystkie linie w każdym pliku, potrzebuje tylko zatrzymać się na x
th jeden i działa jeden wc
(i potencjalnie jeden rm
) polecenie dla każdego pliku.
Dzięki GNU awk
możesz zwiększyć wydajność dzięki:
x=10
find . -type f -readable -exec awk -v x="$x" -v ORS='\0' '
FNR == x {nextfile}
ENDFILE {if (FNR < x) print FILENAME}' {} +|
xargs -r0 echo rm -f
(ponownie usuń, echo
gdy będzie szczęśliwy).
To samo z perl
:
x=10 find . -type f -readable -exec perl -Tlne '
if ($. == $ENV{x}) {close ARGV}
elsif (eof) {print $ARGV; close ARGV}' {} +
Wymień print
się unlink
jeśli szczęśliwy.
sh
? 2. Czy jestwc -l < "$file"
szybszy niżwc -l "$file"
? 3. Skąd sh zna wartość$x
, która jest zdefiniowana w wywołującej powłoki Bash?sh
jest zawarta w tym wbudowanym skrypcie$0
, na przykład do komunikatów o błędach.wc -l "$file"
wypisałby nazwę pliku, której tutaj nie chcemy i działałbywc
nawet, jeśli pliku nie można otworzyć.$x
jest eksportowany dofind
(x=10 find...
), który sam przekazuje go dosh
.find: -readable: unknown primary or operator
.bash
.bash
to tylko interpreter wiersza poleceń, alefind
implementacji.-readable
Jest to rozszerzenie GNU, nie jest dostępna w systemie OS / Xfind
. Służy tylko do ograniczenia plików, które są czytelne (nie będziesz w stanie uzyskać liczby wierszy dla plików nieczytelnych). Możesz pominąć to dla pierwszego, wtedy po prostu otrzymujesz komunikaty o błędach podczas otwierania plików dlawc
plików, których nie można odczytać.Dla kompletności, poza AWK możesz również użyć GNU sed, aby osiągnąć ten sam wynik:
Co powoduje, że wiersz poleceń jest nieco bardziej zwięzły.
Wyjaśnienie
źródło