W skrypcie bash chciałbym uchwycić standardowe dane wyjściowe długich linii poleceń po linii, aby można je było analizować i zgłaszać podczas działania polecenia początkowego. Oto skomplikowany sposób, w jaki mogę to sobie wyobrazić:
# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &
#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
#capture the last lines in temp file and determine if there is new content to analyse
tail /tmp/tmp$$.out
# ...
sleep 1 s # sleep in order not to clog cpu
ps cax | grep longcommand > /dev/null
done
Chciałbym wiedzieć, czy istnieje prostszy sposób na zrobienie tego.
EDYTOWAĆ:
Aby wyjaśnić moje pytanie, dodam to. longcommand
Wyświetla jego stan linia po linii raz na sekundę. Chciałbym uchwycić wynik przed longcommand
ukończeniem.
W ten sposób mogę potencjalnie zabić, longcommand
jeśli nie przyniesie oczekiwanych rezultatów.
Próbowałem:
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Ale whatever
(np. echo
) Wykonuje się dopiero po longcommand
zakończeniu.
Odpowiedzi:
Po prostu potokuj polecenie w
while
pętli. Istnieje wiele niuansów, ale w zasadzie (wbash
lub w dowolnej powłoce POSIX):Innym głównym gotcha z tym (innym niż te
IFS
poniżej) jest próba użycia zmiennych z pętli po jej zakończeniu. Wynika to z faktu, że pętla jest faktycznie wykonywana w podpowłoce (po prostu inny proces powłoki), z którego nie można uzyskać dostępu do zmiennych (również kończy się, gdy pętla się kończy, w którym to momencie zmienne całkowicie znikają. Aby to obejść, możesz to zrobić:Przykładem Hauke za ustawiania
lastpipe
nabash
inne rozwiązanie.Aktualizacja
Aby upewnić się, że przetwarzane są dane wyjściowe polecenia „tak, jak to się dzieje”, można użyć
stdbuf
do ustawienia procesustdout
na buforowanie linii.Spowoduje to skonfigurowanie procesu do zapisywania jednego wiersza na raz w potoku zamiast wewnętrznego buforowania jego wyników w bloki. Uwaga: program może samodzielnie zmienić to ustawienie wewnętrznie. Podobny efekt można uzyskać za pomocą
unbuffer
(częściexpect
) lubscript
.stdbuf
jest dostępny w systemach GNU i FreeBSD, wpływa tylko nastdio
buforowanie i działa tylko w przypadku aplikacji nie-setuid, non-setgid, które są dynamicznie połączone (ponieważ używa sztuczki LD_PRELOAD).źródło
IFS=
jest potrzebnebash
, sprawdziłem to po raz ostatni.line
(w takim przypadku wynik jest wstawiany$REPLY
bez przycinania spacji wiodących i końcowych). Spróbuj:echo ' x ' | bash -c 'read line; echo "[$line]"'
i porównaj zecho ' x ' | bash -c 'IFS= read line; echo "[$line]"'
lubecho ' x ' | bash -c 'read; echo "[$REPLY]"'
źródło