2011-07-15 7 views
5

Prosty skrypt tutaj:BASH: Najlepsza architektura odczytu z dwóch strumieni wejściowych

a) stale czytać z gniazda i przechowywać wartości w tablicy asocjacyjnej
b) stale odczytywać wartości ze standardowego wejścia i odpowiedzi t/f, jeśli już istnieją w tablicach asocjacyjnych, to są przypadkowe zdarzenia, nie są w żaden sposób powiązane.

Sztuką jest dostęp do tablicy z obu podprocesów (gdyż wprowadzenie procesu w tle ikra go jako podproces)

myślę za najlepszą strategię i wystąpić kilka pomysłów, ale zastanawiam się, czy ktoś ma nic lepszego na myśli:

1) przekierować wejście od gniazda do stdin jako podproces i obsługiwać zarówno wejść w jednej pętli while (rozmiary danych są małe, < 30 znaków, więc myślę, że pozostaną one atomowy ?).
2) odczytać gniazdo, a następnie STDIN z małymi (0,1?) Wartościami limitu czasu odczytu, aby naśladować nieblokujące wejścia/wyjścia.
3) AKTUALIZACJA: zapisz dane gniazda do pliku (faktycznie drugi proces zapisz go bezpośrednio do pliku), a następnie za każdym razem, gdy pojawi się żądanie sprawdzenia, czy wartość istnieje, przetwórz wpisy w pliku, dodanie ich do tablicy (użyj blokady pliku).

+0

Wygląda na to, że masz odpowiedni pomysł. Czy jest jakiś powód, aby zrobić to w bashie, w przeciwieństwie do innego języka? – Slartibartfast

+0

Dobre pytanie. Nie, nie ma żadnego powodu, aby używać bash w innym języku. Bash jest prosty i mały, to jedyny powód (i mam 5 innych skryptów basha wykonujących podobne zadania uwierzytelniania/rejestrowania/zarządzania użytkownikami, więc miło jest utrzymywać jednolitą platformę) –

Odpowiedz

4

Bash nie jest odpowiednim narzędziem do tego. Ten problem jest zwykle rozwiązywany za pomocą wywołań systemowych select(2) lub poll(2), które umożliwiają jednoczesne oczekiwanie na wiele deskryptorów plików bez wirowania. Bash nie ma interfejsu do żadnego z nich.

Polecam przy użyciu języka skryptowego takich jak Python lub Perl (co odpowiada Ci, naprawdę), który zapewnia interfejs z select lub poll (na przykład moduł Pythona select).

+0

Dzięki za ustawienie mnie prosto na to.Masz rację. Po przyjrzeniu się temu więcej i byciu facetem z java, podniosę się i podejmę wysiłek, by wykonać to zadanie w świetny sposób. Na mojej liście życzeń już od jakiegoś czasu się uczę. –

2

Nie wiem, czy jest to w pełni praktyczne i wystarczająco atomowe w opisanym kontekście, ale używając modelu klient/serwer i nazwanych potoków można utworzyć pętlę while, która rozróżnia linie pochodzące od fifo lub stdin .

Serwer stale odczytuje linie z gniazda (/tmp/to), a także linie od stdin (które są przekierowywane na serwer przez /tmp/to).

Jednak linie od stdin są oznaczane przez bajt del (\177) jako pierwszy bajt linii.

Następnie klient (w tle) while-loop używa tego pierwszego bajtu linii do rozróżnienia linii o różnym pochodzeniu.

# terminal window 1 

# server 
(
rm -f /tmp/to /tmp/from 
mkfifo /tmp/to /tmp/from 
while true; do 
    while IFS="" read -r -d $'\n' line; do 
    printf '%s\n' "${line}" 
    done </tmp/to >/tmp/from & 
    bgpid=$! 
    exec 3>/tmp/to 
    exec 4</tmp/from 
    trap "kill -TERM $bgpid; exit" 0 1 2 3 13 15 
    wait "$bgpid" 
    echo "restarting..." 
done 
) & 
serverpid=$! 

# client 
(
exec 3>/tmp/to; 
exec 4</tmp/from; 
while IFS="" read -r -d $'\n' <&4 line; do 
    if [[ "${line:0:1}" == $'\177' ]]; then 
    printf 'line from stdin: %s\n' "${line:1}" 
    else  
    printf 'line from fifo: %s\n' "$line" 
    fi 
done & 
trap "kill -TERM $"'!; exit' 1 2 3 13 15 
while IFS="" read -r -d $'\n' line; do 
    # can we make it atomic? 
    # sleep 0.5 
    # dd if=/tmp/to iflag=nonblock of=/dev/null # flush fifo 
    printf '\177%s\n' "${line}" 
done >&3 
) 
#kill -TERM $serverpid 


# terminal window 2 
echo hello > /tmp/to