2012-09-07 20 views
6

Rozważmy prostą pętlę:Proste Bash - dla f in *

for f in *.{text,txt}; do echo $f; done 

chcę echo ważny tylko nazwy plików. Użycie zmiennej $ f w skrypcie wszystko działa świetnie, chyba że nie ma żadnych plików tego rozszerzenia. W przypadku zbioru pustego, $ f jest ustawione na * .text i wyżej Echos Line:

*.text 
*.txt 

zamiast echem niczym. Stwarza to błąd, jeśli próbujesz użyć $ f dla wszystkiego, co oczekuje prawdziwej prawdziwej nazwy pliku, a zamiast tego dostaje *.

Jeśli są jakieś pliki pasujące do symbolu wieloznacznego, więc nie jest to pusty zestaw, wszystko działa tak, jakbym chciał. na przykład

123.text 
456.txt 
789.txt 

Jak mogę to zrobić bez błędów i bez pozornie nadmiernej złożoności pierwszego ciągu pasującego do $ f dla gwiazdki?

Odpowiedz

13

Ustaw opcję nullglob jon.

$ for f in *.foo ; do echo "$f" ; done 
*.foo 
$ shopt -s nullglob 
$ for f in *.foo ; do echo "$f" ; done 
$ 
+0

To jest dokładnie to, czego szukałem. Dzięki! – user1610022

3

Można sprawdzić, czy plik rzeczywiście istnieje:

for f in *.{text,txt}; do if [ -f $f ]; then echo $f; fi; done 

czy można użyć polecenia find:

for f in $(find -name '*.text' -o -name '*.txt'); do 
    echo $f 
done 
+0

Testowanie, czy plik $ f faktycznie jest wystarczająco dobrym plikiem. Jest to jednak dodatkowy test, którego miałem nadzieję uniknąć. – user1610022

0

Ponadto, jeśli można sobie pozwolić na wykorzystanie zewnętrznego ls można uciec jego wyniki za pomocą zestawu

+0

Nie działa, jeśli nazwy plików zawierają spacje. – choroba

+0

Które można naprawić, ustawiając '$ IFS' poprawnie. W przeciwieństwie do opcji nullglob może się to zdarzyć dość bezpiecznie w skrypcie powłoki bez wywoływania shopt. – ThePadawan

+0

Proszę pokazać, jak. Ponadto 'shopt' jest wbudowany, więc nie nazywasz go" out ". – choroba