Sprawdź, czy określony typ / rozszerzenie pliku istnieje w katalogu

84

W jaki sposób możesz sprawdzić, czy pliki o określonym rozszerzeniu znajdują się w katalogu za pomocą bash?

Coś jak

if [ -e *.flac ]; then 
echo true; 
fi 
Wurlitzer
źródło

Odpowiedzi:

104
#!/bin/bash

count=`ls -1 *.flac 2>/dev/null | wc -l`
if [ $count != 0 ]
then 
echo true
fi 
JeremyWeir
źródło
9
Hej Thomas, co powiesz na dodanie lepszego rozwiązania pytania zamiast po prostu głosowania przeciw.
JeremyWeir
8
Thomas, twój przykład, dlaczego go nie używać, to użycie ls -l, moja odpowiedź używals -1
JeremyWeir
10
Ta odpowiedź nie analizuje danych wyjściowych, tylko liczy wiersze wyjściowe i jestem prawie pewien, że nawet jeśli w nazwie pliku są dziwne znaki, ls -1wydrukuje jedną linię na plik
JeremyWeir
2
Zliczanie wierszy jest analizowane. I zwróci niepoprawną liczbę, jeśli jakiekolwiek pliki zawierają \n(i tak, jest to poprawne w nazwach plików).
marcelm
1
Módl się, powiedz nam więc, jaki magiczny znak musiałby być w nazwie pliku, aby wiersz się nie liczył?
yeoman
27
#/bin/bash

myarray=(`find ./ -maxdepth 1 -name "*.py"`)
if [ ${#myarray[@]} -gt 0 ]; then 
    echo true 
else 
    echo false
fi
wkl
źródło
5
Ten jest fajny, ponieważ po ich znalezieniu możesz coś zrobić z plikami.
ephsmith
+1 do zawijania podpowłoki w nawiasach, aby uczynić myarray zmienną tablicową. W przeciwnym razie, jeśli find nie zwróci wyniku, ${#myarray[@]}to 1
shaffooo.
można również uprościć, używając ls -1 *.pyzamiast find
JrBenito
Jeśli którykolwiek z plików ma spację w nazwie, jedno wystąpienie będzie traktowane jako dwa.
Jon Griffith
16

Używa ls (1), jeśli nie istnieją żadne pliki flac, ls zgłasza błąd i skrypt kończy pracę; w przeciwnym razie skrypt jest kontynuowany, a pliki mogą być przetwarzane

#! /bin/sh
ls *.flac  >/dev/null || exit
## Do something with flac files here
frayser
źródło
4
Aby uzyskać dodatkową ciszę, przekieruj również 2> & 1.
Jasper
6
Wersja if:if ls *.flac >/dev/null 2>&1; then ... fi;
Josiah Yoder
9
shopt -s nullglob
if [[ -n $(echo *.flac) ]]    # or [ -n "$(echo *.flac)" ]
then 
    echo true
fi
Dennis Williamson
źródło
4

Musisz uważać, którą flagę wrzucisz do swojego ifoświadczenia i jaki ma to związek z oczekiwanym wynikiem.

Jeśli chcesz sprawdzić tylko zwykłe pliki, a nie inne typy wpisów systemu plików, będziesz chciał zmienić szkielet kodu na:

if [ -f file ]; then
echo true;
fi

Użycie -fograniczenia ogranicza się ifdo zwykłych plików, podczas gdy -ejest bardziej ekspansywne i będzie pasować do wszystkich typów wpisów systemu plików. Istnieją oczywiście inne opcje, takie jak -dkatalogi itp. Zobacz http://tldp.org/LDP/abs/html/fto.html aby uzyskać dobrą listę.

Jak wskazał @msw, test(tj. [) Dusi się, jeśli spróbujesz podać więcej niż jeden argument. Może się to zdarzyć w twoim przypadku, jeśli glob for *.flaczwrócił więcej niż jeden plik. W takim przypadku spróbuj zawinąć iftest w pętlę, taką jak:

for file in ./*.pdf
do
    if [ -f "${file}" ]; then
    echo 'true';
    break
    fi
done

W ten sposób breakna pierwszym wystąpieniu żądanego rozszerzenia pliku możesz kontynuować pracę nad resztą skryptu.

dtlussier
źródło
1
z wyjątkiem test(aka [) narzeka, jeśli wzorzec rozwija się do więcej niż jednego pliku: „oczekiwano operatora binarnego” lub „za dużo argumentów”
msw
1
@msw - dzięki, nawet nie pomyślałem o tym problemie. Próbowałem zmodyfikować moją odpowiedź, aby wziąć ją pod uwagę.
dtlussier
Powinieneś cytować zmienną, tj. Używać "$file", ponieważ nazwa pliku może zawierać złe znaki, takie jak spacje lub gwiazdki.
Roman Cheplyaka
3
#!/bin/bash
files=$(ls /home/somedir/*.flac 2> /dev/null | wc -l)
if [ "$files" != "0" ]
then
echo "Some files exists."
else
echo "No files with that extension."
fi
Ruel
źródło
3

Najlepsze rozwiązanie (if [ -e *.flac ];)u mnie nie działało, dając:[: too many arguments

if ls *.flac >/dev/null 2>&1; wtedy to zadziała.

Erik Buitenhuis
źródło
3

Możesz użyć -f, aby sprawdzić, czy istnieją pliki określonego typu:

#!/bin/bash

if [ -f *.flac ] ; then
   echo true
fi 
Uzi
źródło
To działa, ale zakopujesz lede - powodem, dla którego działa, jest to, że pojedynczy nawias [(w przeciwieństwie do bardziej powszechnego [[) nie zapobiega globbingowi.
Adrian Petrescu
2
   shopt -s nullglob
   set -- $(echo *.ext)
    if [ "${#}" -gt 0 ];then
      echo "got file"
    fi
ghostdog74
źródło
To jest źle. Po pierwsze, prawdopodobnie miałeś na myśli -gezamiast tego -gt, ponieważ w przeciwnym razie kod nie wykryje pojedynczego pliku. Po drugie, jeśli nie ma plików pasujących do wzorca, każda zgodna powłoka pozostawi ciąg *.extnietknięty, więc nadal otrzymasz jeden „wynik”.
Roman Cheplyaka
$ # to 1 dla pojedynczego pliku i 0 dla braku plików.
frayser
1

tylko bash:

any_with_ext () ( 
    ext="$1"
    any=false
    shopt -s nullglob
    for f in *."$ext"; do
        any=true
        break
    done
    echo $any 
)

if $( any_with_ext flac ); then
    echo "have some flac"
else 
    echo "dir is flac-free"
fi

Używam nawiasów zamiast nawiasów klamrowych, aby upewnić się, że używana jest podpowłoka (nie chcę przebijać bieżących nullglobustawień).

glenn jackman
źródło
1

Oto rozwiązanie wykorzystujące bez zewnętrznych poleceń (tj. Nie ls), ale zamiast tego funkcję powłoki. Przetestowane w bash:

shopt -s nullglob
function have_any() {
    [ $# -gt 0 ]
}

if have_any ./*.flac; then
    echo true
fi

Funkcja have_anyużywa $#do liczenia argumentów, a [ $# -gt 0 ]następnie sprawdza, czy istnieje co najmniej jeden argument. Użycie ./*.flaczamiast tylko *.flacw wywołaniu funkcji have_anyma na celu uniknięcie problemów powodowanych przez pliki o nazwach takich jak --help.

jochen
źródło
1

Aby zakończyć, z zsh:

if [[ -n *.flac(#qN) ]]; then
  echo true
fi

Jest to wymienione na końcu sekcji Wyrażenia warunkowe w podręczniku zsh. Ponieważ [[wyłącza tworzenie nazw plików, musimy wymusić generowanie nazwy pliku, używając (#q)na końcu globalnego ciągu znaków, a następnie Nflagi ( NULL_GLOBopcji), aby wymusić, że wygenerowany ciąg będzie pusty w przypadku braku dopasowania.

Iso
źródło
1

Oto dość proste rozwiązanie:

if [ "$(ls -A | grep -i \\.flac\$)" ]; then echo true; fi

Jak widać, jest to tylko jedna linia kodu, ale działa wystarczająco dobrze. Powinien działać zarówno z bashem, jak i powłoką zgodną z POSIX, taką jak myślnik. Rozróżnia również wielkość liter i nie dba o to, jakie typy plików (zwykłe, dowiązanie symboliczne, katalog itp.) Są obecne, co może być przydatne, jeśli masz jakieś dowiązania symboliczne lub coś w tym rodzaju.

TSJNachos117
źródło
Podoba mi się to, ponieważ ls -AR wykonuje wyszukiwanie rekurencyjne. dobre do przeszukiwania zawartości archiwów zip po rozpakowaniu.
justin cress
0

Próbowałem tego:

if [ -f *.html ]; then
    echo "html files exist"
else
    echo "html files dont exist"
fi

Użyłem tego fragmentu kodu bez problemu dla innych plików, ale dla plików html otrzymałem błąd :

[: too many arguments

Następnie wypróbowałem rozwiązanie zliczania @ JeremyWeir, które zadziałało dla mnie.

Pamiętaj, że będziesz musiał zresetować licznik, jeśli robisz to w pętli:

count=$((0))
GChuf
źródło
0

To powinno działać w każdej skorupie podobnej do przenoszonej:

if [ "$(find . -maxdepth 1 -type f | grep -i '.*\.flac$')" ]; then
    echo true
fi

Działa to również z GNU find, ale IDK, jeśli jest to zgodne z innymi implementacjami find:

if [ "$(find . -maxdepth 1 -type f -iname \*.flac)" ]; then
    echo true
fi
TSJNachos117
źródło