Rekurencyjnie szukaj plików z określonym rozszerzeniem


437

Próbuję znaleźć wszystkie pliki z określonym rozszerzeniem w katalogu i jego podkatalogach za pomocą bash (najnowsza wersja Ubuntu LTS).

Oto, co jest zapisane w pliku skryptu:

#!/bin/bash

directory="/home/flip/Desktop"
suffix="in"

browsefolders ()
  for i in "$1"/*; 
  do
    echo "dir :$directory"
    echo "filename: $i"
    #   echo ${i#*.}
    extension=`echo "$i" | cut -d'.' -f2`
    echo "Erweiterung $extension"
    if     [ -f "$i" ]; then        

        if [ $extension == $suffix ]; then
            echo "$i ends with $in"

        else
            echo "$i does NOT end with $in"
        fi
    elif [ -d "$i" ]; then  
    browsefolders "$i"
    fi
  done
}
browsefolders  "$directory"

Niestety, kiedy uruchamiam ten skrypt w terminalu, mówi:

[: 29: in: unexpected operator

(z $extensionzamiast 'in')

Co tu się dzieje, gdzie jest błąd? Ale ten nawias klamrowy


2
Błąd wynika z brakującego „{”
shrewmouse

Odpowiedzi:


750
find $directory -type f -name "*.in"

jest nieco krótszy niż to wszystko (i bezpieczniejszy - zajmuje się białymi znakami w nazwach plików i nazwach katalogów).

Twój skrypt prawdopodobnie nie działa w przypadku wpisów, które nie mają .w nazwie, dlatego są $extensionpuste.


16
tak, finddomyślnie jest rekurencyjny. możesz ograniczyć głębokości, jeśli chcesz (patrz strona podręcznika).
Mat

1
Chciałbym przekazać wszystkie znalezione pliki jako argumenty do pliku jar. Jak można to zrobić?
przerzuć

8
@flip: to inne pytanie. Opublikuj nowe pytanie, szczegółowo opisując, co chcesz zrobić i co dotychczas próbowałeś.
Mat

Jedna mała poprawka: użyj „* .in” lub \ *. In zamiast „* .in”, ponieważ podwójne cudzysłowy nie zapobiegają rozszerzaniu powłoki. Oznacza to, że twój skrypt nie będzie działał poprawnie, jeśli w bieżącym katalogu znajduje się plik z rozszerzeniem .in.
Shnatsel,

4
@Shnatsel: podwójne cudzysłowy uniemożliwiają rozszerzenie powłoki. Wypróbuj to.
Mat

188
find {directory} -type f -name '*.extension'

Przykład: Aby znaleźć wszystkie csvpliki w bieżącym katalogu i jego podkatalogach, użyj:

find . -type f -name '*.csv'

60

Używana przeze mnie składnia jest nieco inna niż sugerowana przez @Matt:

find $directory -type f -name \*.in

(to jeden klawisz mniej).


1
Skrypt Matta również nie zadziała, jeśli w bieżącym katalogu znajduje się plik z rozszerzeniem .in, podczas gdy twój nadal będzie działał. Zobacz stackoverflow.com/questions/5927369/…
Shnatsel,

4
@Shnatsel ten komentarz (a zatem i twój) jest po prostu błędny.
gniourf_gniourf

1
@gniourf_gniourf Powinieneś podać jakieś odniesienie do swojego oświadczenia, w przeciwnym razie można po prostu argumentować: „Nie, mylisz się”. Ale w rzeczywistości masz rację: gnu.org/software/bash/manual/html_node/Double-Quotes.html
Murmel

@ user1885518: Myślę, że to powinien być facet, który twierdzi, że skrypt nie działa, który powinien podać kilka przykładów, w których skrypt się nie powiedzie. Tak właśnie robię, gdy zostawiam komentarze tam, gdzie są zepsute skrypty: zwykle dotyczą cytatów i nazw plików zawierających spacje, znaki nowej linii, globusy itp., A ja dokładnie wyjaśniam, dlaczego jest zepsuty.
gniourf_gniourf

2
Podanie odniesienia jest zawsze dobrym sposobem na dyskusję, nie zależy od tego, kto był pierwszy. Powinien, powinieneś.
Murmel

14

Bez użycia find:

du -a $directory | awk '{print $2}' | grep '\.in$'

3
To grepnie jest tak naprawdę konieczne. awkma wyrażenia regularne i może ograniczyć wynik do wartości pasujących do wzorca.
Kenster,

Ta metoda jest niezwykle przydatna, jeśli przechodzisz przez setki terabajtów. Przetwarzanie polecenia Znajdź trwa zbyt długo. To zaczyna się natychmiast.
Protonova,

1
awk|grepjest anty-wzorem. Niech awk zrobi grepping.
Jens

10
  1. Tam {brakuje pobrowsefolders ()
  2. Wszystko $inpowinno być$suffix
  3. Linia z cutpokazuje tylko środkową część front.middle.extension. Powinieneś przeczytać instrukcję obsługi ${varname%%pattern}i znajomych.

Zakładam, że robisz to jako ćwiczenie skryptów powłoki, w przeciwnym razie findrozwiązanie już zaproponowane jest dobrym rozwiązaniem.

Aby sprawdzić poprawną składnię powłoki, bez uruchamiania skryptu, użyj sh -n scriptname.



7

Chociaż użycie findpolecenia może być przydatne tutaj, sama powłoka zapewnia opcje umożliwiające spełnienie tego wymagania bez narzędzi innych firm. bashPowłoka zapewnia rozszerzoną opcję pomocy glob za pomocą którego można uzyskać nazwy plików pod rekurencyjnych ścieżek że mecz z rozszerzeniami, które chcesz.

Rozszerzona opcja jest tym, extglobco należy ustawić za pomocą shoptopcji przedstawionej poniżej. Opcje są włączone z -sobsługą i wyłączone z -uflagą on . Dodatkowo możesz użyć kilku opcji więcej, tj. nullglobW którym niezrównany glob zostaje całkowicie zmieciony, zastąpiony zestawem zerowych słów. I globstarktóry pozwala na przeszukanie przez wszystkich katalogów

shopt -s extglob nullglob globstar

Teraz wystarczy utworzyć wyrażenie glob, aby uwzględnić pliki określonego rozszerzenia, które można wykonać w sposób opisany poniżej. Używamy tablicy do wypełniania wyników globalnych, ponieważ przy prawidłowym cytowaniu i rozwinięciu nazwy plików ze znakami specjalnymi pozostałyby nienaruszone i nie uległyby uszkodzeniu z powodu podziału słów przez powłokę.

Na przykład, aby wyświetlić listę wszystkich *.csvplików w ścieżkach rekurencyjnych

fileList=(**/*.csv)

Opcja **polega na ponownym przechodzeniu przez podfoldery i *.csvjest rozszerzeniem globalnym w celu włączenia dowolnego pliku wymienionych rozszerzeń. Teraz do drukowania rzeczywistych plików, po prostu zrób

printf '%s\n' "${fileList[@]}"

Używanie tablicy i poprawne cytowanie rozszerzenia jest właściwym sposobem, gdy jest używane w skryptach powłoki, ale do użytku interaktywnego można po prostu użyć lswyrażenia glob jako

ls -1 -- **/*.csv

Można to bardzo dobrze rozszerzyć, aby pasowało do wielu plików, tj. Plik kończący się wieloma rozszerzeniami (tj. Podobnie jak dodawanie wielu flag w findpoleceniu). Dla przykładu rozważmy przypadek konieczności, aby wszystkie pliki graficzne rekurencyjnych czyli rozszerzeń *.gif, *.pnga *.jpgwszystko, czego potrzebujesz do Is

ls -1 -- **/+(*.jpg|*.gif|*.png)

Można to bardzo dobrze rozszerzyć, aby również miało negatywne wyniki. Przy tej samej składni można użyć wyników globu, aby wykluczyć pliki określonego typu. Załóżmy, że chcesz wykluczyć nazwy plików z powyższymi rozszerzeniami, możesz to zrobić

excludeResults=()
excludeResults=(**/!(*.jpg|*.gif|*.png))
printf '%s\n' "${excludeResults[@]}"

Konstrukt !()jest operacją negowania, która nie obejmuje żadnego z rozszerzeń plików wymienionych w środku, i |jest operatorem naprzemiennym, tak jak jest używany w bibliotece Rozszerzonych wyrażeń regularnych, aby wykonać dopasowanie LUB globów.

Zauważ, że ta rozszerzona obsługa globów nie jest dostępna w powłoce bourne POSIX i jest ona specyficzna dla ostatnich wersji bash. Więc jeśli zastanawiasz się nad przenośnością skryptów działających w POSIX i bashpowłokach, ta opcja nie byłaby właściwa.


6

Aby znaleźć wszystkie pom.xmlpliki w bieżącym katalogu i wydrukować je, możesz użyć:

find . -name 'pom.xml' -print


0
for file in "${LOCATION_VAR}"/*.zip
do
  echo "$file"
done 

1
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, dlaczego i / lub jak ten kod odpowiada na pytanie, poprawia jego długoterminową wartość.
rollstuhlfahrer
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.