Próbuję napisać if
instrukcję, aby sprawdzić, czy są jakieś pliki pasujące do określonego wzorca. Jeśli w katalogu znajduje się plik tekstowy, powinien on uruchomić dany skrypt.
Mój kod obecnie:
if [ -f /*.txt ]; then ./script fi
Proszę podać kilka pomysłów; Chcę uruchomić skrypt tylko, jeśli jest .txt
w katalogu.
shell-script
files
wildcards
test
użytkownik40952
źródło
źródło
/
? Ponadto brakuje Ci wcześniej średnikafi
.find
jak wyjaśniono tutaj na temat przepełnienia stosu .Odpowiedzi:
zwróciłoby wartość prawdy tylko wtedy, gdy istnieje jeden (i tylko jeden) plik,
/
którego nazwa się nie kończy,.txt
i jeśli jest to zwykły plik lub dowiązanie symboliczne do zwykłego pliku.Jest tak, ponieważ symbole wieloznaczne są rozszerzane przez powłokę przed przekazaniem do polecenia (tutaj
[
).Więc jeśli istnieje
/a.txt
i/b.txt
,[
zostanie przekazany 5 argumentów:[
,-f
,/a.txt
,/b.txt
i]
.[
skarżyłby się wtedy na-f
zbyt wiele argumentów.Jeśli chcesz sprawdzić, czy
*.txt
wzorzec rozwija się do co najmniej jednego nie ukrytego pliku (zwykłego lub nie):shopt -s nullglob
jestbash
specyficzny, ale muszle podobaksh93
,zsh
,yash
,tcsh
mają te same oświadczenia.Zauważ, że znajduje te pliki, czytając zawartość katalogu, wcale nie próbuje uzyskać dostępu do tych plików, co czyni go bardziej wydajnym niż rozwiązania, które wywołują polecenia takie jak
ls
lubstat
na tej liście plików obliczonych przez powłokę.Standardowy
sh
odpowiednik to:Problem polega na tym, że w przypadku powłok Bourne lub POSIX, jeśli wzorzec nie pasuje, rozwija się do siebie. Jeśli więc zostanie
*.txt
rozwinięty*.txt
, nie wiesz, czy to dlatego, że nie ma.txt
pliku w katalogu, czy dlatego, że istnieje jeden plik o nazwie*.txt
. Korzystanie[*].txt *.txt
pozwala na rozróżnienie między nimi.źródło
[ -f /*.txt ]
jest dość szybki w porównaniu docompgen
.[ -f /*.txt ]
byłby w błędzie, ale w moim teście katalog zawierający3425
pliki,94
z których nie są ukrytymi plikami txt,compgen -G "*.txt" > /dev/null 2>&1
wydaje się być tak szybki jakset -- *.txt; [ "$#" -gt 0 ]
(20,5 sekundy dla obu, jeśli powtórzę 10000 razy w moim przypadku).Zawsze możesz użyć
find
:Wyjaśnienie:
find .
: przeszukaj bieżący katalog-maxdepth 1
: nie przeszukuj podkatalogów-type f
: przeszukuj tylko zwykłe plikiname "*.txt"
: wyszukaj pliki z rozszerzeniem.txt
2>/dev/null
: przekieruj komunikaty o błędach na/dev/null
| grep -q .
: grep dla dowolnego znaku, zwróci false, jeśli nie znaleziono znaków.&& ./script
: Wykonaj./script
tylko, jeśli poprzednie polecenie zakończyło się pomyślnie (&&
)źródło
find
zwraca fałsz tylko wtedy, gdy ma problemy ze znalezieniem plików, a nie, jeśli nie znajdzie żadnego pliku. Chcesz potokować wyjście,grep -q .
aby sprawdzić, czy coś znajdzie.chmod a-x .
.Możliwym rozwiązaniem jest także wbudowane Bash
compgen
. To polecenie zwraca wszystkie możliwe dopasowania wzorca globowania i ma kod wyjścia wskazujący, czy jakieś pliki pasują.Znalazłem to pytanie, szukając szybszych rozwiązań.
źródło
LC_ALL=C compgen -G "*.txt" > /dev/null
.Oto jeden linijka, aby to zrobić:
pliki istnieją
pliki nie istnieją
To podejście wykorzystuje operatory
||
i&&
w bash. Są to operatory „lub” i „i”.Więc jeśli polecenie stat zwróci wartość
$?
równą 0, wówczasecho
wywoływane jest pierwsze , jeśli zwraca 1,echo
to wywoływane jest drugie .zwraca wyniki ze stat
To pytanie jest szeroko omówione przy przepełnieniu stosu:
źródło
stat
kiedyls -d
można to zrobić?ls -d
wyświetla katalog? Wydawało się, że nie działa, gdy próbowałemls -d *.pl
na przykład wyświetlić katalog z plikami .&&
przezls *.txt
i ona również będzie działać. Upewnij się, że wysłałeś stdout i stderr na/dev/null
adres sugerowany przez @slm.ls *.txt
i nie ma żadnych plików obecny w katalogu to zwróci$? = 2
, który będzie nadal działać z jeśli potem, ale był to jeden z powodów, dla których wybierastat
sięls
. Chciałem 0 dla sukcesu, a 1 dla niepowodzenia.ls -d
jest lista katalogów zamiast ich zawartości. Takls -d
samo dziejelstat
się z plikiem, tak jak GNUstat
. To, jakie niezerowe komendy zakończenia działania zwracają się po awarii, jest specyficzne dla systemu, nie ma sensu przyjmować na nich założeń.Jak zauważa Chazelas, skrypt nie powiedzie się, jeśli interpretacja symboli wieloznacznych pasuje do więcej niż jednego pliku.
Istnieje jednak pewna sztuczka, której używam ( nawet nie bardzo mi się to podoba ) do poruszania się:
Jak to działa?
Rozwijanie symboli wieloznacznych będzie pasować do tablicy nazw plików, otrzymamy pierwszą, jeśli istnieją, w przeciwnym razie zerowa, jeśli nie będzie pasować.
źródło
.txt
plików typu regularnego . Spróbuj na przykład późniejmkdir a.txt; mkfifo b.txt; echo regular > c.txt
.Proste jak:
wc -l
zlicza linie w rozwiniętym znaku wieloznacznym.źródło
ls
danych wyjściowych i prawie nigdy nie sprawdzać$?
bezpośrednio, ponieważif
już to robi. Również użyciewc
do sprawdzenia, czy coś się stało, jest podobnie źle skierowane.Podoba mi się poprzednie rozwiązanie macierzowe, ale mogłoby to stać się marnotrawstwem przy dużej liczbie plików - powłoka użyłaby dużej ilości pamięci do zbudowania tablicy i tylko pierwszy element byłby testowany.
Oto alternatywna struktura, którą przetestowałem wczoraj:
$ cd /etc; if [[ $(echo * | grep passwd) ]];then echo yes;else echo no;fi yes $ cd /etc; if [[ $(echo * | grep password) ]];then echo yes;else echo no;fi no
Wydaje się, że wartość wyjściowa z grep określa ścieżkę przez strukturę kontrolną. To również sprawdza przy użyciu wyrażeń regularnych, a nie wzorców powłoki. Niektóre z moich systemów mają polecenie „pcregrep”, które pozwala na znacznie bardziej wyrafinowane dopasowanie wyrażeń regularnych.
(Edytowałem tę odpowiedź, aby usunąć „ls” w podstawieniu polecenia po przeczytaniu powyższej krytyki za parsowanie).
źródło
jeśli chcesz użyć klauzuli if, oceń liczbę:
źródło