fájlméret változásának figyelése BASH-ban [megoldva]

Sziasztok.

Tárgy szóban ezt találtam ki egy logfile méretváltozásának ultraprimitív figyelésére:

#!/bin/bash

aa (){
a=`ls -l /opt/gps.minicom | awk 'BEGIN {FS=" "}{print $5}'`
echo $a
}

bb (){
b=`ls -l /opt/gps.minicom | awk 'BEGIN {FS=" "}{print $5}'`
echo $b
}

while [ "$a"-"$b" != "0" ]; do
aa
sleep 4
bb
echo "$a"-"$b" novekedik
done

exit 0

szerintetek szebben megoldható ez?
Mert ez nekem működik ugyan, de nem tetszik. Ronda.

Hozzászólások

Ah, most látom, hogy ARM-ra akarod. A pacman nem ad semmit? Pedig létezik a csomag. Persze arra is figyelj, hogy milyen architektúrára kell, mert nem mindegy!

olyasféle hibaüzenetet dob, mintha 64 bitesre lett volna forgatva

És ebből már mindent értünk is... ha akarsz segítséget, akkor segíts, hogy segíthessünk! Pontosan tudni kellene, milyen arm-ra akarod (rpi*?), és az az "olyasféle hibaüzenet"-et jó lenne pontosan tudnunk.

Az aa és a bb függvény csak annyiban különbözik, hogy az egyik az a értékét, a másik pedig a b értékét állítja.
Ha a bash, ls, awk-hoz ragaszkodunk (nem pedig inotify, ahogy fentebb már jelezték), akkor inkább így:

function size_of_file() {
  ls -l ...
}

new=`size_of_file`
while [ "${new}"-"${old}" != "0" ]; do
  old=${new}
  sleep 4
  new=`size_of_file`
  echo ${new}-${old} novekedik
done

Azon gondolkodom, hogy ha van két sring, amelyet egy kötőjel közbeiktatásával összefűzöl, abból hogyan lesz egy olyan string, amely a "0" karaktart tartalmazza.

while ((new-old!=0))

vagy

while [ $((new-old)) -ne 0 ]

de akár

while [ $((new-old)) != 0 ]

Ez utóbbi stringet néz, de a 0 az stringként is úgy néz ki, hogy "0".

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

A bash helyettesít, tehát ha az egyik hossz 12345 meg a másik is, akkor valami ilyesmi lesz belőle:

[ 12345-12345 != 0 ]

Ez pedig teljesül, hiszen az első egy 11 karakter hosszú string, a második pedig 1 karakter hosszú, így nem egyenlők. Nem számolja ki numerikusan. Viszont a mondandód lényege, hogy azonos függvényt nem deklarálunk többször, vagy csak a visszatérés változója miatt többször, az rendben van. :)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Picit szebb lenne, ha a függvény paramétere lenne a filenév, nem pedig be lenne drótozva. Ugyanakkor nem kell függvény, mert a stat már az:

old="$new"
new="`stat -c '%s' /opt/gps.minicom`"

Ebben az esetben, mivel számokról van szó, amelyben biztosan nem lesz mondjuk szóköz, nem kellenek az idézőjelek, de én legtöbbször kiírom őket.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE


function size_of_file() {
  stat -c '%s' /opt/gps.minicom
}

new=`size_of_file`
while [ "${new}"-"${old}" != "0" ]; do
  old=${new}
  sleep 4
  new=`size_of_file`
  echo ${new}-${old} novekedik
done

Változtattam a fájlon, majd csaltam és visszaváltoztattam eredeti méretre. Csak azért is tovább echozta a növekedést..

---
--- A gond akkor van, ha látszólag minden működik. ---
---

Ahogy írták, inotify. Ugyanakkor úgy emlékszem, az inotify nagyon nem szereti, ha kirántják alóla a file-t, tehát például törlik.

A másik dolog, hogy scriptekben az ls helett hasznosabb a stat. Itt például:

stat -c '%s' /opt/gps.minicom

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Ez igaz, használom is. Valami olyasmi gondom volt, hogy figyelhetem ugyan a törlést, de ha azt az alkönyvtárat törlik, amelyben a file törlését figyelem, akkor megdöglik. Nyilván a file törlését éppen úgy vizsgálja, hogy valójában az őt tartalmazó alkönyvtárhoz nyúl a kernel, módosítja a bejegyzéseket, de ha nincs hol nézni, akkor azt hiszem, a hibakezelés nem valami korrekt. Talán az egész daemon újraindítása segített csak.

Én egyébként arra használom, hogy vannak általam karbantartott gépek, amelyek a bekapcsolásukkor elküldenek nekem e-mailben néhány technikai infót, többek között a külső, publikus IP címüket is. A Claws Mail-em lehozza a levelet, maildirben tárol. Létrejön a mail file, az inotify ezt kiszúrja, majd indítja a scriptemet, amelyik kiszedi a levélből a host nevet és az IP címet, majd a hosts file-omba írja. Ha van már host név, cseréli a címet, ha nincs, a végéhez fűzi a bejegyzést. Így, amikor ssh-n el akarom érni a gépet, hivatkozhatok a host nevére, s még ddns sem kell. :)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Valamit lehet, hogy benéztem akkoriban, amikor foglalkoztam vele. Megoldottam, mostanában teszi a dolgát, azt sem tudom, hogy van, mert megy. Viszont az a gyanúm, ha friss esemény van, s közvetelnül utána állítanám le a gépet, a systemd jelzi, hogy az inotify miatt nem lehet, vár talán 90 másodpercet, aztán lerúgja agresszven, talán SIGKILL-el.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Nem tudom, a systemd mit benazik csinal, a kernel reszerol biztosan nincs ilyen megkotes. Amikor esemeny van, azt a kernel eltarolja egy pufferbe, a programod pedig egy file descriptoron keresztul kiolvassa. Amikor a program kap egy SIGINT/SIGTERM-et, azonnal kilep(het), nincs szukseg semmi kesleltetesre.

inotify mellett döntöttem, gondolván arra, hogy ezt nem ismerem, így legalább megismerem. Rémesen kevés leírást és példát találtam.

inotifywait -c -m -e create,close_write /tmp/log.nmea >> /tmp/log.nmea.temp

Ezzel figyelem most a fájl változásait, majd a /tmp/log.nmea.temp figyelésével indítom a scriptemet. Nos, ez egy jó nagy marhaság eddig, hoszen kétszeres figyelést hajtok végre...

Ötletem sincs, hogy az inotifyt hogyan van értelme használni.

---
--- A gond akkor van, ha látszólag minden működik. ---
---

A man-t nézted? Ott van 3 példa, amiből talán a mésodikat akarod használni ("Example 2 A short shell script to efficiently wait for httpd-related log messages and do something appropriate."). Az iwatch-ot nézted? Lehet, hogy az jobban tetszene (és célszerűbb is) a közvetlen parancsfuttatással. Annak a man-jában is vannak példák.

Manualokat is néztem, nem sokra jutottam.

Most ezen kínlódok:

#!/bin/bash
while true; do

inotifywait -e close_write /tmp/test && echo "valtozott"

done

Ha változtatom a file-t, az echo nem fut le.

---------
Amilyen vesztes vagyok, armv7h-re iwatch-ot nem találok, legfeljebb rpm-ben, az meg nem jó az Arch lunixomhoz. Tárolóim a pacmanhoz szét vannak barmolva, szóval zajlik az élet.

---
--- A gond akkor van, ha látszólag minden működik. ---
---

Azt hiszem, félreértettél. Amit írtam, az nem a megoldás, hanem csak egy bemutató, annak jelzése, hogy működnie kellene.
Neked nincs szükséged sleepre, meg háttérben futtatásra. Amit eredetileg írtál, annak jónak kellene lennie, de csak így tudtam a legegyszerűbben megmutatni.

De akkor 2 terminálból, elindítva az eredeti scripted, és közben a másik terminálról változtatva a file

1.)


$ cat bzsproba
#!/bin/bash
while true; do

inotifywait -e close_write /tmp/test && echo "valtozott"

done
$


$ ./bzsproba
Setting up watches.
Watches established.
/tmp/test CLOSE_WRITE,CLOSE
valtozott
Setting up watches.
Watches established.

2.)


$ echo uj >>/tmp/test
$

A te példakódodat módosítva kezdett el működni nálam, így annak is meg szoktam köszönni a segítséget, akinek hatására beindult a dolog.

Már ledet is villogtatok rpi-n ezzel:


#!/bin/bash

#/etc/profile-ba irva:
#echo 27 > /sys/class/gpio/export
#sleep 0.5
#echo out > /sys/class/gpio/gpio27/direction
#

while true; do
 (inotifywait -e close_write /opt/gps.minicom && \
 	 echo 0 > /sys/class/gpio/gpio27/value && \
	 sleep 1 && \
	 echo 1 > /sys/class/gpio/gpio27/value && \
	 sleep 0.05  &) ; sleep 5 
done

# ronda, de fut.

---
--- A gond akkor van, ha látszólag minden működik. ---
---

Desktop gépen nekem az inotify-jal kapcsolatban van egy /etc/incron.d/incron.systable file-om, benne egy

/home/locsemege/.claws-mail/Mail/mailfiók/inbox IN_CREATE /usr/local/bin/shosts $@ $#

bejegyzés. Azt, hogy mi mit jelent, itt találod. Az shosts egy saját scriptem, amely megkapja paraméterül a beeső e-mail filenevét, s ez a script dolgozza fel a levelet.

Az inotify-ban, incrond-ben az a jó, hogy nem kell háttérben állandóan futtatnod valamit, s pollingolni, hanem eseményvezérelt. Jön az esemény amelyet filerendszeren történő változás triggerel megadott feltételekkel, s ennek hatására kezd el futni a scripted. Esetleg arra kell figyelni, ha az események túl gyorsan jöhetnek, a script egy második példánya ne fusson, amíg az előző még igen.

A systemd systemctl parancsával természetesen engedélyeztem az incrond szolgáltatás futását.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Igen, a több példányban futás csapdájába estem, ráadásul képtelen vagyok arra, hogy rábírjam az inotify-t hogy a parancssori kimenetét a /dev/null-ba írja és ne az ssh-terminálomba, ahol ezután az mc is beromantikásodik..

---
--- A gond akkor van, ha látszólag minden működik. ---
---

A fentiek óta küzdök, mégsem megy.


#!/bin/bash

led()
{
  echo 0 > /sys/class/gpio/gpio27/value
  sleep 5 
  echo 1 > /sys/class/gpio/gpio27/value
}

while true; do
  inotifywait -e close_write /opt/gps.minicom && led() &
  sleep 5
done

Az inotifywait kimenete folyamatosan megjelenik terminalban:
"Setting up watches.
Watches established."

és a led() el sem indul.
Lehet, hogy inkább le kell mondanom erről a lefvillogtatásról, örülnöm kéne, ha kikapcsoláskor már be tudom kapcsolni és ég, míg a shutdown le nem fut.

---
--- A gond akkor van, ha látszólag minden működik. ---
---

Lehet, hogy inkább le kell mondanom erről a lefvillogtatásról

Ne légy gyáva! Én olyat még nem láttam, hogy egy számítógéppel, amellyel be lehet kapcsolni egy LED-et, villogtatni már nem lehet. Most tegyük félre azt az esetet, hogy lehet olyan hardware-t tervezni, amellyel csak bekapcsolni lehet valamit, kikapcsolni nem, de itt ez nem áll fenn.

Az átirányítást én valahogy így intézném:

inotifywait -e close_write /opt/gps.minicom &>/dev/null && led &

Az nem lehet, hogy a /sys/class/gpio/gpio27/value-t csak a root-nak van joga írni?

Ami azt illeti, semmi okot nem látok arra, hogy háttérben futtasd a led() függvényt, s ezzel még egy shell-t indíts másik pid-del. Valahogy úgy csinálnám, hogy ha true az inotifywait, akkor futtatnám a led() függvényt, ellenkező esetben várnék 5 másodpercet, s így semmit sem kell háttérben futtatni. Nem néztem meg az inotifywait működését, azt feltételezem, hogy a programod abból a szempontból jó, hogy akkor true, amikor kell.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Hozzátéve ahhoz, amit locsemege írt:

"inotifywait -e close_write /opt/gps.minicom && led() &"
Miért van a függvény meghívásakor zárójelpár?

"Az inotifywait kimenete folyamatosan megjelenik terminalban"
Miért van háttérben indítva? Így nyilván egyre több inotifywait fog futni párhuzamosan (a sleep miatt 5 másodpercenként plusz egy).
Egyáltalán miért kell a sleep a ciklusba?


$ cat  bzsproba
#!/bin/bash

led()
{
  echo LED
}

while true; do
  inotifywait -o /dev/null -e close_write /opt/gps.minicom 2>/dev/null && led
done
$

Ez 3 darab "echo uj >>/opt/gps.minicom" hatására:


$ ./bzsproba
LED
LED
LED
^C
$

Ó, jaj, azt a triviális hibát ki sem szúrtam, mármint a zárójeleket. :-/ A saját hozzászólásomból ki is szedtem, korábban csak copy-paste-eltem az övéből hibásan.

Nem néztem meg, ez az inotifywait várakozik, vagy azonnal visszatér true-val vagy false-szal? Azért kérdezem, mert ha azonnal visszatér, úgy indokolt lehet a sleep, mert ha nincs benne, egy egy CPU magot 100 %-ra fog terhelni, illetve, ha osztoznia kell más process-szel a futásidőn, akkor kevesebbre, de lényeg, hogy a CPU mag nem fog pihenni. Persze, ha várakozik, akkor nem szóltam. Magam nem olvastam el a manual-ját.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE