Wiem, że mogę czekać na spełnienie warunku bash, wykonując:
while true; do
test_condition && break
sleep 1
done
Ale tworzy 1 podproces przy każdej iteracji (uśpieniu). Mogłem ich uniknąć, wykonując:
while true; do
test_condition && break
done
Ale zużywa dużo procesora (zajęte oczekiwanie). Aby uniknąć podprocesów i zajętego czekaniem, wymyśliłem poniższe rozwiązanie, ale wydaje mi się brzydkie:
my_tmp_dir=$(mktemp -d --tmpdir=/tmp) # Create a unique tmp dir for the fifo.
mkfifo $my_tmp_dir/fifo # Create an empty fifo for sleep by read.
exec 3<> $my_tmp_dir/fifo # Open the fifo for reading and writing.
while true; do
test_condition && break
read -t 1 -u 3 var # Same as sleep 1, but without sub-process.
done
exec 3<&- # Closing the fifo.
rm $my_tmp_dir/fifo; rmdir $my_tmp_dir # Cleanup, could be done in a trap.
Uwaga: w ogólnym przypadku nie mogę po prostu użyć read -t 1 var
bez fifo, ponieważ zużyje standardowe wejście i nie będzie działać, jeśli standardowe wejście nie jest terminalem ani rurą.
Czy mogę uniknąć podprocesów i zajętego oczekiwania w bardziej elegancki sposób?
bash
shell-script
sleep
jfg956
źródło
źródło
true
jest wbudowany i nie tworzy podprocesu w bash. zajęty czekaniem zawsze będzie źle.true
, pytanie zaktualizowane.read -t 1 var
.sleep
jak w pierwszym przykładzie. Drugi, choć może działać, nie będzie łatwo nikomu się dostosowywać w przyszłości. Prosty kod ma również większy potencjał bezpieczeństwa.Odpowiedzi:
W nowszych wersjach
bash
(przynajmniej v2) wbudowane mogą być ładowane (przezenable -f filename commandname
) w czasie wykonywania. Wiele takich ładowalnych wbudowanych plików jest również dystrybuowanych ze źródłami bash isleep
jest wśród nich. Oczywiście dostępność może się różnić w zależności od systemu operacyjnego (a nawet komputera). Na przykład w openSUSE te wbudowane funkcje są dystrybuowane za pośrednictwem pakietubash-loadables
.Edycja: napraw nazwę pakietu, dodaj minimalną wersję bash.
źródło
sleep
jako wbudowany. Dzięki.Tworzenie wielu podprocesów jest złą rzeczą w wewnętrznej pętli. Tworzenie jednego
sleep
procesu na sekundę jest OK. Nie ma w tym nic złegoJeśli naprawdę chcesz uniknąć zewnętrznego procesu, nie musisz utrzymywać otwartego fifo.
źródło
mkdir
ją tak, jak to zrobionomktemp
(jeśli nie, jest to warunek wyścigu). Dotyczy to również tego,while ! test_condition;
co jest lepsze niż moje początkowe rozwiązanie.Ostatnio musiałem to zrobić. Wymyśliłem następującą funkcję, która pozwoli bashowi spać na zawsze bez wywoływania jakiegokolwiek programu zewnętrznego:
UWAGA: Wcześniej opublikowałem wersję, która za każdym razem otwierałaby i zamykała deskryptor pliku, ale zauważyłem, że w niektórych systemach, robiąc to setki razy, sekunda w końcu się blokuje. Zatem nowe rozwiązanie utrzymuje deskryptor pliku między wywołaniami funkcji. Bash i tak wyczyści go przy wyjściu.
Można to nazwać tak jak / bin / sleep i będzie ono spało przez żądany czas. Wywołany bez parametrów, zawiesi się na zawsze.
Tutaj jest mój blog z nadmiernymi szczegółami
źródło
read -t 10 < <(:)
wraca natychmiast,read -t 10 <> <(:)
czekając pełne 10 sekund, ale wciąż nie rozumiem.read -t 10 <> <(:)
czym oznacza<>
?W
ksh93
lubmksh
,sleep
jest wbudowane powłoki, tak Alternatywą może być zastosowanie tych skorup, a niebash
.zsh
ma równieżzselect
wbudowane (ładowanezmodload zsh/zselect
), które mogą spać przez określoną liczbę setnych sekund zzselect -t <n>
.źródło
Jak powiedział użytkownik yoi , jeśli w twoim skrypcie jest otwarte stdin , to zamiast uśpienia 1 możesz po prostu użyć:
W wersji Bash 4.1 i nowszych możesz użyć liczby zmiennoprzecinkowej, np
read -t 0.3 ...
Jeśli w skrypcie stdin jest zamknięte (skrypt jest wywoływany
my_script.sh < /dev/null &
), musisz użyć innego otwartego deskryptora, który nie generuje danych wyjściowych po wykonaniu odczytu , np. standardowe :Jeśli w skrypcie cały deskryptor jest zamknięty ( stdin , stdout , stderr ) (np. Ponieważ jest wywoływany jako demon), to musisz znaleźć dowolny plik, który nie generuje danych wyjściowych:
źródło
read -t 1 3<&- 3<&0 <&3
jest taki sam jakread -t 0
. To tylko czytanie ze standardowego limitu czasu.Działa to zarówno z powłoki logowania, jak i powłoki nieinteraktywnej.
źródło
read -t 10 <> <(:)
.Czy naprawdę potrzebujesz fifo? Powinno również działać przekierowanie standardowego wejścia na inny deskryptor pliku.
Inspirowane przez: Przeczytaj dane wejściowe w bash w pętli while
źródło
Nieznaczna poprawa wyżej wymienionych rozwiązań (na których to oparłem).
Zmniejszyło potrzebę użycia fifo, a zatem nie ma potrzeby sprzątania.
źródło
read -t 10 <> <(:)
.