Glob rekurencyjny?


80

Chciałbym napisać coś takiego:

$ ls **.py

aby uzyskać wszystkie nazwy plików .py, rekurencyjnie chodź po hierarchii katalogów.

Nawet jeśli do znalezienia są pliki .py, powłoka (bash) daje następujące dane wyjściowe:

ls: cannot access **.py: No such file or directory

Jest jakiś sposób na zrobienie tego, co chcę?

EDYCJA: Chciałbym sprecyzować, że nie jestem zainteresowany konkretnym przypadkiem ls, ale pytanie dotyczy składni globalnej.

Odpowiedzi:


98

Aby wykonywać rekurencyjne globusy w bash, potrzebujesz globstarfunkcji z wersji bash 4 lub wyższej.

Z strony podręcznika bash:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

Na przykładowy wzór:

shopt -s globstar
ls **/*.py

2
Polecam również włączenienullglob
glenn jackman

6
@glennjackman Ale przed włączeniem nullglobzdecydowanie zalecam przeczytanie następujących ostrzeżeń .
Serge Stroobandt,

2
^ Przeniesiono tutaj ostrzeżenia .
usandfriends

1
W wersji bash 3.2 wc -l {**,.}/*.pydziała dobrze
Raphael

@Raphael Dokładnie sprawdziłem informacje o wydaniu i zdecydowanie mówi, że został wprowadzony w wersji 4.0. Być może twoja dystrybucja ma dla niej poprawkę? IIRC RHEL 5 miał backport niektórych funkcji. Warto też wspomnieć, że minęło 9 lat od wydania bash 4 ...
jordanm

10
find . -name '*.py'

** nie robi nic więcej niż jeden *, oba działają w bieżącym katalogu


Ciekawy. Chociaż bardziej skupiam się na samej składni glob, ponieważ muszę go używać w pliku konfiguracyjnym (dołącz dyrektywę). Nie potrzebuję listy plików.
Paolo

2
@Doug O'Neal, to już nie jest prawda. bash został skopiowany że cechą zsh (choć przyjęła składni bliższy ksh93 i jak ksh, nie obsługuje nazw plików kwalifikatorów zsh jest jeszcze co ogranicza jego użyteczność)
Stéphane Chazelas

Jest wiele rzeczy, które możesz zrobić, findjeśli nie masz bash 4. Przykłady: yourcommand `find . -name '*.py'`(zwróć uwagę na backticks); find . -name '*.py' -exec yourcommand {} \;.
Mars,

5

Od wersji Bash 4 (w tym również zsh) dodano nową opcję globbing ( globstar), która traktuje wzór **inaczej, gdy jest ustawiony.

Pasuje do wzoru wieloznacznego i zwraca pasujące nazwy plików i katalogów, zastępując wzór wieloznaczny w poleceniu dopasowanymi elementami.

Zwykle, gdy używasz **, działa podobnie *, ale rekursywnie rekursuje wszystkie katalogi (jak pętla).

Aby sprawdzić, czy jest włączony, sprawdź to przez shopt globstar(w skryptach użyj shopt -q globstar).

Przykład **.pydziałałby tylko dla bieżącego katalogu, ponieważ nie zwraca listy katalogów, które mogą być powtarzane, dlatego właśnie musisz użyć wielu symboli wieloznacznych na poziomie katalogu **/*.py, aby mógł on wejść głębiej.

Proszę znaleźć na SO kilka testów składniowych, które zrobiłem dla znalezienia wszystkich plików rekurencyjnie.

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.