Myślałem, że to będzie proste - ale okazuje się bardziej złożone niż się spodziewałem.
Chcę iterować wszystkie pliki określonego typu w katalogu, więc piszę:
#!/bin/bash
for fname in *.zip ; do
echo current file is ${fname}
done
Działa to tak długo, jak w katalogu jest co najmniej jeden pasujący plik . Jeśli jednak nie ma pasujących plików, otrzymuję to:
current file is *.zip
Potem spróbowałem:
#!/bin/bash
FILES=`ls *.zip`
for fname in "${FILES}" ; do
echo current file is ${fname}
done
Chociaż ciało pętli nie wykonuje się, gdy nie ma plików, otrzymuję błąd z ls:
ls: *.zip: No such file or directory
Jak napisać pętlę, która czysto nie obsługuje pasujących plików?
shopt -s nullglob
przed uruchomieniem pętli for.FILES=
; for fname in "${FILES}"...
for fname in *.zip ; do....
for file in *.zip
, nie`ls ...`
. Sugestia @ cuonglm jest taka, że*.zip
rozwija się do zera, gdy wzorzec nie pasuje do żadnego pliku.ls
bez argumentów wyświetla bieżący katalog.ls
ogół należy unikać analizowania wyniku : Dlaczego nie parsowaćls
? ; zobacz także link u góry tej strony do artykułu ParsingLs BashGuide .Odpowiedzi:
W
bash
możesz ustawić tęnullglob
opcję, aby wzorzec, który nie pasuje do niczego, „znikał”, zamiast traktować go jako ciąg literalny:W skrypcie powłoki POSIX wystarczy sprawdzić, czy
fname
istnieje (i jednocześnie[ -f ]
sprawdzić, czy jest to zwykły plik (lub dowiązanie symboliczne do zwykłego pliku), a nie inne typy, takie jak katalog / fifo / device ...):Wymień
[ -f "$fname" ]
się[ -e "$fname" ] || [ -L "$fname ]
jeśli chcesz pętli nad wszystkimi (nie-ukryty) pliki, których nazwa kończy się.zip
niezależnie od ich rodzaju.Wymień
*.zip
się.*.zip .zip *.zip
jeśli również rozważyć ukryte pliki, których nazwa kończy się.zip
.źródło
shopt -s nullglob
nie działało dla mnie na Ubuntu 17.04, ale[ -f "$fname" ] || continue
działało dobrze.bash
.W komentarzu tutaj wspominasz o wywołaniu funkcji ...
źródło
Użyj znajdź
Musisz to wyeksportować swoją funkcję powłoki,
export -f
aby to zadziałało. Terazfind
wykonuje,bash
która wykonuje twoją funkcję powłoki i pozostaje tylko na bieżącym poziomie katalogu.źródło
Zamiast:
Próbować:
W ten sposób, jeśli ls zawiedzie (co ma miejsce w twoim przypadku), grepuje nieudane wyjście i zwraca jako pustą zmienną.
Możesz dodać do tego logikę, aby zwracała „Nie znaleziono pliku”
W ten sposób, jeśli poprzednie polecenie zakończyło się powodzeniem (zostało zakończone z wartością 0), wydrukuje bieżący plik, w przeciwnym razie wypisze „Nie znaleziono plików”
źródło
grep
) zamiast próby rozwiązania problemu za pomocą lepszego narzędzia (find
) lub zmiany odpowiedniego ustawienia dla obecnego rozwiązania (zshopt -s nullglob
)shopt -s nullglob
nie działa. Próbowałemfind
podczas sprawdzania mojej odpowiedzi i nadal nie udało mi się. Myślę, że z powodu wywozu powiedział Dani.