2016-10-14 12 views
6

Potrzebuję utworzyć skrypt basha, aby poczekać na utworzenie pliku. Skrypt użyje polecenia sleep w pętli while, aby okresowo sprawdzać plik co 10 sekund. Wydrukuj wiadomość podczas oczekiwania. Wyświetl zawartość pliku po utworzeniu pliku. Poniżej jest to, co starałem się wdrożyć i oczywiście nie działa. W tym momencie nie jestem do końca pewien, jak postępować.Oczekiwanie na utworzenie pliku w Bash

#!/bin/bash 
let file=$1 

while '(-f ! /tmp/$1)' 
do 
     sleep 10 
     echo "still waiting" 
done 

echo "Content of the file $1:" 
+0

'' (...) ''jest STRING, który sprowadza się do' while true'. spróbuj 'while [! -f/tmp/$ 1]' lub podobnie. –

+1

@MarcB, co? Nie "podczas gdy prawda" w ogóle; to 'while while false', ponieważ ten ciąg nie jest poprawnym poleceniem. Jeśli znajdował się w teście, * wtedy * może być. –

+1

BTW, w przyszłości, należy rozważyć użycie 'bash -x yourscript' aby dowiedzieć się, co dzieje się w trakcie realizacji - w tym przypadku, że wykazały, że jechaliśmy prosto z' '(! -f/tmp/$ 1) "' to 'echo" Treść pliku $ 1: "', wykluczając tym samym problem z 'sleep' (ponieważ w ogóle nie był uruchamiany). –

Odpowiedz

11

Problem dotyczy testu, a nie snu (jak postawiono hipotezę w oryginalnym pytaniu). Najmniejsza możliwa poprawka może wyglądać następująco:

while ! test -f "/tmp/$1"; do 
    sleep 10 
    echo "Still waiting" 
done 

Pamiętaj składnię dla while pętli:

while: while COMMANDS; do COMMANDS; done 
    Expand and execute COMMANDS as long as the final command in the 
    `while' COMMANDS has an exit status of zero. 

to znaczy, pierwszy argument dany while, rozwijając pętlę, jest to polecenie; musi przestrzegać tych samych reguł składni, co każde inne polecenie powłoki.

-f jest ważna jako argument do test - komenda, która jest również dostępna pod nazwą [, wymagające ] jako ostatni argument stosowany w tej nazwie - ale to nie jest ważne jak polecenia w sobie - i gdy jest przekazywany jako część łańcucha, nie jest to nawet słowo powłoki, które może być przetwarzane jako pojedyncza nazwa polecenia lub argument.

Po uruchomieniu '(-f ! /tmp/$1)' jako polecenia, w cudzysłowie powłoka szuka rzeczywistego polecenia o dokładnie tej nazwie (łącznie ze spacjami). Prawdopodobnie nie masz pliku o nazwie '/usr/bin/(-f ! /tmp/$1)' w ścieżce PATH lub innym poleceniu o tej nazwie, więc zawsze zawiedzie - natychmiast zamknie pętlę while.


Przy okazji - jeśli jesteś skłonny do kodu OS specyficzne, istnieją inne metody niż przy użyciu sleep czekać na plik istnieć. Weźmy na przykład, inotifywait z pakietu inotify-tools:

while ! test -f "/tmp/$1"; do 
    echo "waiting for a change to the contents of /tmp" >&2 
    inotifywait --timeout 10 --event create /tmp >/dev/null || { 
    (($? == 2)) && continue ## inotify exit status 2 means timeout expired 
    echo "unable to sleep with inotifywait; doing unconditional 10-second loop" >&2 
    sleep 10 
    } 
done 

o skorzystanie z interfejsu opartego inotify jest, że zwraca natychmiast po zmianie systemu plików, a nie ponosić narzut odpytywania (co może być szczególnie istotna jeśli zapobiega snu z systemu).


Nawiasem mówiąc, niektóre praktyczne Uwagi: (tzn. "/tmp/$1")

  • Cytowanie ekspansji w nazwach zapobiega nazwy spacjami lub literowych przed rozwinięciem się w wielu różnych argumentów.
  • Korzystanie >&2 na echo polecenia przeznaczona do logowania do spożycia przez ludzi utrzymuje stderr dostępny do spożycia programowej
  • let służy do matematyki, nie przypisań ogólnego przeznaczenia.Jeśli chcesz użyć "$file", nic złego - ale przypisanie powinno być tylko file=$1, bez poprzedzającego let.
+2

Dla użytkowników komputerów Mac, można użyć 'fswatch' zamiast' inotifywait': 'fswatch --event Created --event Updated "$ INPUT_DIR"' – Julian