Uzyskaj listę nazw katalogów z funkcją find


35

Wiem, że mogę to zrobić, aby uzyskać listę nazw katalogów:

find . -type d -maxdepth 1 

Dane wyjściowe wyglądają następująco:

.
./foo
./bar

Wolę wpis bez ./. Czy istnieje sposób, aby znaleźć, aby wyświetlać tylko surowe nazwy?

Próbowałem wysłać listę do statystyki, aby ją sformatować, ale to daje mi ten sam wynik:

find . -type d -maxdepth 1 -print0 | xargs -0 stat -f '%N'

więc chcesz foo bar ...wszystko na jednej linii bez ./frontu?
Levon

Czy to wyłącznie ze względów kosmetycznych / estetycznych, czy próbujesz zrobić coś z efektem?
jw013,

Odpowiedzi:


42

W GNU findmożesz użyć -printfopcji:

find . -maxdepth 1 -type d -printf '%f\n'

Jak zauważył Paweł w komentarzach, jeśli nie chcesz, aby bieżący katalog był na liście, dodaj -mindepth 1np .:

find . -mindepth 1 -maxdepth 1 -type d -printf '%f\n'

Nie mogę znaleźć żadnej wzmianki o tej -printfopcji w najnowszej specyfikacji POSIX i zastanawiam się, jak przenośna jest ...
rahmu

@rahmu: Zostało to przetestowane przy pomocy GNU find. Żadna z printfopcji nie jest wymieniona przez POSIX i wydaje się, że nie są obsługiwane przez niektóre inne findwersje. GNU find można zainstalować w większości miejsc, więc w tym sensie jest przenośny.
Thor

1
dodaj także, -mindepth 1jeśli chcesz się pozbyć.
Paweł Prażak

18

Aktualizacja:

Krótsza alternatywa:

 find . -maxdepth 1 -type d | cut -c 3-

Podadzą ci nazwy, po jednej w wierszu, bez żadnych ukośników


4
@ downvoter .. głosowanie bez wyjaśnienia nie pomaga nikomu (OP, SO ani mnie). Jest to funkcjonalne rozwiązanie pytania OP. Z przyjemnością naprawię błąd, jeśli zostanie wskazany lub poprawiony, ale wymaga to konstruktywnej informacji zwrotnej, a nie tylko anonimowego „kliknięcia”.
Levon

1
To ja głosowałem za odrzuceniem, gdy twoja odpowiedź obejmowała analizę ls. W tym samym czasie zamieściłem link, dlaczego jest to zły pomysł na inną odpowiedź, która została usunięta. W tym czasie były tylko 2 odpowiedzi, a powód wydawał się oczywisty. Cieszę się, że zwróciłeś uwagę na dwuznaczność, a oto moje wyjaśnienie. Dla przypomnienia, oddałem głos w głosowaniu pozytywnym, ponieważ zgadzam się z twoją obecną odpowiedzią.
rahmu

@rahmu Wyjaśnienie twojego komentarza w innym pytaniu nie jest dla mnie pomocne (i tylko dla ciebie oczywiste). Ponadto, chociaż jest to lepsze rozwiązanie, rozwiązanie, które opublikowałem wcześniej, działało dobrze (tak, znam twój link „nie używaj ls” - ale nie we wszystkich przypadkach ma zastosowanie). Jeśli masz przeciwny przykład tego, dlaczego moje początkowe rozwiązanie nie zadziałało, chciałbym to wiedzieć (tak, abym mógł się z tego czegoś nauczyć), w przeciwnym razie po prostu publikujesz link i nie oferujesz nic konstruktywnego.
Levon

Zastanów się, czy \nw nazwie katalogu znajduje się nazwa, której nie możesz użyć do jej odzyskania (co robiłeś, kiedy cię oceniłem). Jest kilka przypadków, w których lsnie zachowuje się niebezpiecznie i prawie zawsze bezpieczniej jest użyć innego sposobu.
rahmu

9

Korzystając z GNU find, możesz użyć -mindepth, aby zapobiec dopasowaniu find do bieżącego katalogu:

find . -type d -maxdepth 1 -mindepth 1

Ponieważ nie robisz tego rekurencyjnie, możesz użyć globu bash:

echo */

Dodanie trailing / do globu spowoduje dopasowanie tylko katalogów.


1
*/brakuje plików kropek i zawiera dowiązania symboliczne. To może, ale nie musi stanowić problemu.
Gilles „SO- przestań być zły”

@Gilles - Zawsze będzie brakować dowiązań symbolicznych, ale pliki kropkowe zależą od tego, czy ustawiony jest plik kropkowy.
jordanm,

6

Pozwól sedusunąć te dwa znaki:

find . -maxdepth 1 -type d | sed -e 's/^\.\///'


2

Zwykle używam:

find * -type d

Ale nie wiem, czy to właściwy sposób na robienie tego, co chcesz.


1
Jeśli zamierzasz pozwolić powłoce rozwinąć wszystkie nazwy plików, po co w ogóle używać find?
jordanm

@jordanm Aby wybrać tylko katalogi. echo */zrobiłby to samo, mniej więcej (pomija pliki kropek i zawiera dowiązania symboliczne), ale wtedy joachim pyta, jak usunąć finał /.
Gilles „SO- przestań być zły”

0

W systemie AIX parametr „maxdepth” nie działa.

Ogólnie rzecz biorąc, działa to dla mnie:

find ./ -type d | cut -d"/" -f2 | sort -u


0

To, czego szukasz, nazywa się basename, ignoruje strukturę katalogów unix

Przykład poniżej:

find /any/path/you/want -maxdepth 1 -type d -exec basename {} \;

wykluczy dla danych wyjściowych nawet ścieżkę katalogu, usuwając konieczność cd przed uruchomieniem polecenia


Niektóre dodatkowe informacje:

Podałbym -execjako argument, aby zamiast tego znaleźć |(potok) inną komendę dla danych wyjściowych (unikając drugiej komendy przechodzącej przez każdą linię wyjściową, mówiąc, że w zależności od danych wyjściowych może poprawić wydajność skryptu)

UWAGA: findopcje niepozycjonowane (-maxdepth wpływa na testy określone przed nim, a także testy określone po nim).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.