Processz kilövése bash scriptből?

Processz kilövése bash scriptből?

Hozzászólások

Ti ugye write-only modban dolgoztok? Nem vlagos, hogy pidof, meg killall nem jo, mert azonos nevu tobb is lehet? (Gy. k. az adott alkalmazasbol futhat meg par masik is.)

(Off: ha lesz kicsit tobb idom, ragodom meg a dolgon erdemben is.)

[quote:62c557ec15="Zahy"]Ti ugye write-only modban dolgoztok? Nem vlagos, hogy pidof, meg killall nem jo, mert azonos nevu tobb is lehet? (Gy. k. az adott alkalmazasbol futhat meg par masik is.)

(Off: ha lesz kicsit tobb idom, ragodom meg a dolgon erdemben is.)

Nem kell hozza nagy esz, hogy rajojj, ehhez az kell, hogy valamiben kulonbozzenek az "azonos" processzek. Kiveve, ha kozvetlen Te (azaz a scripted) inditottad el a process-t($!).
Tehat valami modon kulonbseget kell talalni a processek kozott monnyuk a ps afx kimeneteben. Arra ra lehet greppelni, meg awk-zni es boldogsag.
Te honnan tudod, hogy melyik process-t akarod kiloni? Azon az uton ki tudja deriteni a scripted is a pid-et.

Azert nem ennyire egyszeru a dolog - a $$ a shell pidje, nem a hatterbe kuldott parancse.

Vágod a témát :)

Viszont az a fuser-es megoldás (aminek annyira örültem) nem fenékig tejfel. Hogy mennyire nem, arra akkor jöttem rá, amikor a szkriptet FreeBSD-n próbáltam futtatni.

Úgyhogy az elegáns fuser helyett maradt egy béna fstat:
fstat "$fajl.log" | head -2 | tail -1 | awk '{ print $3 }'

Ez vegytiszta környezetben egyelőre működni látszik.

[quote:66abffb049="tolmi"][quote:66abffb049="Zahy"](Gy. k. az adott alkalmazasbol futhat meg par masik is.)

Nem kell hozza nagy esz, hogy rajojj, ehhez az kell, hogy valamiben kulonbozzenek az "azonos" processzek. ...
Te honnan tudod, hogy melyik process-t akarod kiloni? Azon az uton ki tudja deriteni a scripted is a pid-et.

Hát erről beszélek. Ha egyszer ugyanaz a szkript fut kétszer, akkor elég nehéz kívülrül kideríteni (bár pl. a PPID mezőket nyomon követve el lehet jutni az eredeti szülőhöz)
Ja, és nem kell hozzá nagy ész, hogy észrevegyük, hogy ez nem az én problémám, csak arra akartam rávilágítani, hogy az itt válaszolók a problémát se értették meg :-)

[quote:8d90fd789e="Zahy"]
Hát erről beszélek. Ha egyszer ugyanaz a szkript fut kétszer, akkor elég nehéz kívülrül kideríteni (bár pl. a PPID mezőket nyomon követve el lehet jutni az eredeti szülőhöz)

ezert irtam hogy a "ps a_f_x"-re greppelj, mert ott ugye a parent-child viszony is latszik, igaz grafikus formaban, de legalabb egy ps afx nyomattal meg lehet tudni, hogy ki a gyerek es ki a szulo ;)

Részemről én a ps (a)x kimentére gondoltam, és az adott paraméterek alapján történő greppelést. Amennyire én látom a script két futása között a paraméterekben van eltérés, ergo ezek alapján a grep meg kell találja a megfelelő sort. Nekem egy hasonló felállásnál ez már működött...

Babszem.

Kozben nekem is el kellett inditanom egy programot, majd kitalalni, hogy melyik volt az :) En igy csinaltam meg, hatha segit neked:

for pid in `pidof <program binaris>`; do
if [ ! -z "`ps ax | grep $pid | grep <amirol felismered a programot>`" ]; then
echo "A pid: $pid"
fi
done

Huhh :D alig latom hol milyen idezojelek vannak - szerintem majd allitsd nagyobbra a betumeretet ha ugy gondolod ez segithet neked :)

Megjegyzes: A ket grep azert kell, mert kulonben megtalalja sajat magat is a grep :)

Plédául megnézném lsof-fal, hogy a fájlt melyik processz fogja, vagy az adott porton melyik processz kommunikál... Tudom, ez olyan "jobb kézzel fej mögött keresztbe nyúlva vakarom az államat", de működhet... Szerinteem...

[quote:4be851572a="Hijaszu"]for pid in `pidof <program binaris>`; do
if [ ! -z "`ps ax | grep $pid | grep <amirol felismered a programot>`" ]; then
echo "A pid: $pid"
fi
done

Megjegyzes: A ket grep azert kell, mert kulonben megtalalja sajat magat is a grep :)

A jo isten aldja mar meg a programozot. RTFM. kulonos tekintettel a ps p opciojara, ami csak az altalad megadott PID-u processzt irja ki. Szoval a baromi bonyolult ps ax | grep "$pid" helyett talan:
ps p "$pid" kene.

[quote:4389c8aa18="j_szucs"]Nem lehet valahogy legalább azt megoldani, hogy egy szkript
kilövése "magával rántsa" az összes belőle indított processzt is?

[code:1:4389c8aa18] 1 trap 'touch "$F.hiba"' EXIT
2 set -e -C
3 exec 1023>"$F.lock"
4 (
5 trap 'set +e; touch "$F.hiba"; rm -f "$F.lock" "$F.port" "$F"' EXIT
6 ctorrent -p "$PORT" "$F" >| "$F.log" 2>&1
7 touch "$F.letoltve"
8 rm -f "$F.lock" "$F.port"
9 trap - EXIT
10 ) &[/code:1:4389c8aa18]

Magyarázat:

1: "trap handler" installálása: a shell tetszőleges elhagyása (pl. SIGTERM is)
előtt közvetlenül létrehozza az "$F.hiba" file-t.

2: tetszőleges kezeletlen hiba esetén kilép a script-ből (-e) (ez beindítja a
trap handlert!), illetve meglévő file-okat nem csap felül az egyszerű
redirection-nel (>, a -C a noclobber megfelelője). Ez kb. azt jelenti, hogy az
open() syscall-nak át lesz adva egy O_EXCL flag is ">" esetén. Az azonnal
felülírós átirányítás (O_EXCL kikapcsolása) elérhető a ">|" operátorral
továbbra is.

3: A shell-ben megnyitjuk (kimenetre) az 1023-as file descriptort, egy újonnan
létrehozandó file-ra. Ha a file már létezik (fut ez a script ugyanezzel az "$F"
paraméterrel), akkor a "set -e -C" miatt azonnal kilépünk és létrejön a
"$F.hiba". Egyébként (és ez a lényeg) a shell összes jövendő gyereke
örökli ezt a file descriptort (senkit nem zavar, senkinek nem hiányzik ez az 1
db descriptor, stb). A "$F.lock" file üres marad, de ez nem lesz gond, lásd
később.

4 ill. 10: "poor man's daemonize". A subshell a háttérben fog továbbra is
futni, örökli az 1023-as fd-t, illetve az ő gyerekei is öröklik tőle. Eddig az
a lényeg, hogy eddigre már az "előtérben" ellenőrizve lett, hogy a script
egyetlen példányban fut-e erre a "$F" paraméterre. Ha igen, akkor az "előtérből
átmehetünk a háttérbe".

5: legelső dolgunk az érvényben lévő trap handler (ami nem az ->1 alatti, hanem
a default, üres, mivel subshell-ben visszaáll a default-ra) felülbírálása. Ez
igazából bővítést jelent: miután megpróbálja létrehozni a "$F.hiba" file-t,
letörli a lock file-t, a a port file-t, meg magát a file-t. Mindez tetszőleges
shell-elhagyásra érvényes.

6: Elindítjuk a ctorrent-et, a log file-t izomból létrehozva (ha nem akarjuk
truncate-elni a log file-t valamiért, akkor nem >| kell (O_TRUNC), hanem >>
(O_APPEND)). Ha valami gáz van a program futása során, vagy a log file nem
létrehozható (pl. permission denied) stb, akkor az "-e" miatt (->2) a
legfrissebben beállított trap handler (->5) veszi kézbe a dolgot (a parciálisan
letöltött file is megy a kukába), majd a shell kilép. (Ja, a lock file
letörlése rendben van, mivel közvetlenül ezután véget ér az "rm" processz meg a
shell is, tehát a lock file inode-ján a refcount valóban lemegy nullára és
felszabadul a helye.)

7: a ctorrent rendben befejeződött, megpróbáljuk lenaplózni, hogy minden
rendben. Ha nem sikerül, akkor trap handler :), kilépés

8: izomból letöröljük a lock file-t meg a port file-t, a letöltött file viszont
megmarad.

9: töröljük a trap handlert (helyesebben default-ra állítjuk), majd sikeresen
kilépünk.

A már futó script lekérdezéséhez/leállításához természetesen a fuser
parancs a kulcs.

[code:1:4389c8aa18]fuser -v "$F.lock"[/code:1:4389c8aa18]

Pontosan azokat a processzeket fogja megmutatni, amelyek az "$F" érdekében
dolgoznak.

[code:1:4389c8aa18]fuser -k -TERM -v "$F.lock"[/code:1:4389c8aa18]

Kinyiffantja a "$F" érdekében tevékenykedő processzeket (a shell-ben a trap
handler le fog futni)

Az 1023 helyett más fd-t is választhatsz, két szempontra figyelj: férjen be az
"ulimit -S -n" alá, ugyanakkor legyen elég magas, mert van néhány
braindead program, ami képes és lezár olyan fd-ket, amiket nem is ő nyitott
meg.

A fenti "technika" nekem még a saját hotplug script-em megírásánál jött jól,
amikor azt akartam elérni, hogy egy új script instance azonnal abortálja
el az összes korábbi példányát. Ezt így oldja meg (a LOCKFILE folyamatosan
létezik):

while fuser -v -k LOCKFILE; do :; done
exec 1023<LOCKFILE

A while ciklus értelme az, hogy a fuser mindaddig "igaz"-at ad vissza, amíg
legalább 1 processz volt, amit meg lehetett szignálozni (itt SIGKILL-lel, nincs
szükségem trap handler-re, mivel az új példány második dolga az, hogy ismert
kezdőállapotba hozza az érintett alrendszert (az elsőt lásd lejjebb)). Olyan
ütemezés is lehetséges ugyanis, hogy a ciklus (ami gyakorlatilag egy busy wait)
10-15-ször is lefut (és 10-15-ször is "pending"-be teszi a SIGKILL-t az előző
példánynál és annak összes gyerekénél), mire a kiirtandó processzek végre
beütemeződnek és végetérnek (ezt meg akarom várni az új példánnyal). Ezután az
új példány hajlandó kilépni a ciklusból, majd első dolga azonnal átvenni a
stafétabotot, hogy nagyon szűk legyen az a window, amikor fut ugyan egy
példány, de a LOCKFILE-on nem lóg senki (lehetővé kell tenni, hogy a következő
instance azonnal kinyírhassa az aktuálist). A "-v" értelme pedig az, hogy az
egész script futása naplózódik, innen tudom, hogy valóban előfordul
olyan ütemezés, amit leírtam.

Kosz :D legalabb mostmar ezt is tudom :D neha en is elnezhetek dolgokat :D

Ember! És én még azt hittem, hogy tudok shell scriptet írni... Ez nem semmi. Respect!!! :D

Babszem

Köszönet mindenkinek, különösen lacos-nak az értékes ötletekért!

Már látom hogy a legegyszerűbb megoldás (szintén lacos egyik ötlete) a fuser parancs lesz.
Ez a parancs megadja azt a lehetőséget, hogy ne kelljen két szkript:
a) a ctorrent-et a szkriptből elindítom a háttérbe küldve, de átirányítva a kimenetét egy $fajl.log fájlba
b) ezután néhány másodpercig sleep-eltetem a szkriptet (nem hajt a tatár), majd a fuser paranccsal megnézem, hogy mi a $fajl.log fájlt használó processz pid-je

Ha netán nem jönne létre a log fájl, akkor ugyan nem tudom meg a ctorrent pid-jét, de ez meg olyan generális gubanca utalna, ami nem csak azt az egy ctorrent processzt érinti (pl. nincs szabad hely, nem megfelelő jogosultságok), tehát ekkor mehet a "killall ctorrent" és a szkript leállása fatális hibával.

Még egyszer köszi a segítséget!

Láma vagyok, soha nem írtam komoly shell scriptet.(ezért az utsó pár hozzászólást át se olvastam, mert kukkot se értek belőle:))
De nem az a legegyszerűbb megoldás, h csinálsz a ctorrentre egy symlinket mondjuk symlink2 névvel, és azt indítod. Akkor a ps kimenetben a másik név lesz, és máris egyszerűen meg van különböztetve a te processed...

(ha hülyeséget mondtam, vagy félreértettem a problémát, akkor lőjetek le, de valami nagy kaliberű cuccal, h ne szenvedjek sokáig:))

Ez eddig a legszellemesebb megoldas :) ha valami temporalis allomanynevvel szimlinkelsz akkor garantaltan egyedi lesz azt a pidoffal visszakeresni teljesen egyertelmu :D
Tetszik :D
Megjegyzem :D

[quote:3c81d0ada9="Hijaszu"]Azert nem ennyire egyszeru a dolog - a $$ a shell pidje, nem a hatterbe kuldott parancse.

De ha a gyerek process kiirja egy fajlba azt utana vissza tudod olvasni a foprocessbol... Vagy named pipe...

Ebbe a hibaba mar en is beleestem :) probald ki :D az nem a processz lesz hanem a processz futtato shell pidje - a demon programokat meg altalaban nem erdeklik, ha kilovod az indito shelljuket attol meg futni fognak :) En legalabbis ezt tapasztaltam :)

Ha egy wrapper scriptben így indítok el egy programot (a ctorrent bittorrent klienst):

((ctorrent -p $ujport "$fajl" >"$fajl.log" 2>&1 && touch "$fajl.letoltve") || (touch "$fajl.hiba"); rm "$fajl.lock" "$fajl.port") &
pid=$!
akkor ki lehet később lőni pontosan ezt a ctorrent processzt ugyanazon szkriptben valami trükkel?

Nekem sehogy se jön össze:

A) természetesen nem jó a "killall ctorrent", mert nekem csak ezt az egy ctorrent processzt szabad kilőni (egyidőben több is futhat belőle)

B) nem jó a "kill $pid" sem, mert a fenti pid változóba úgy látszik nem a ctorrent pid-je kerül, hanem egy másik bash processzé (a komplex parancs ugyanis egyszerre 3 processzt is indít: 2 bash + 1 ctorrent); a bash processz kilövése viszont a tapasztalataim szerint nem állítja le a ctorrent processzt.

A kérdést úgy is megfogalmazhatnám, hogy át lehet-e írni úgy a fenti parancsot, hogy:

a) a ctorrent továbbra is a háttérben fusson,
b) a ctorrent processz indulásakor a pid-je (és csak azé) kerüljön a "$fajl.lock" fájlba,
c) hibamentes kilépésekor jöjjön létre a "$fajl.letoltve" fájlt,
d) ha hiba miatt lépett ki, jöjjön létre a "$fajl.hiba" fájlt,
e) tetszőleges kilépésekor törlődjenek a "$fajl.lock" és "$fajl.port" fájlok?

Van a fentiekre valami frappáns megoldás egyetlen szkriptben, vagy csak a fenti parancs "kiszervezésével" azaz külön szkriptbe helyezésével lehet ezt mind megoldani?

Szerkesztve:
Basszus, most látom, hogy a ctorrent még akkor is tovább fut a "kill $pid" után, ha az őt indító komplex parancsot egy külön, szintén a háttérben futó szkriptbe teszem, és annak a szkriptnek a pid-jét lövöm ki.
Akkor most szépen elakadtam. :(
Tudna valaki segíteni? Nem lehet valahogy legalább azt megoldani, hogy egy szkript kilövése "magával rántsa" az összes belőle indított processzt is?

Csak egy tipp, de mi volna, ha a megfelelő processz pidjét egy ps kimentéből greppelve szednéd össze?

HTH:
Babszem

Nem tudom milyen kernelt használsz, nem biztos hogy működni fog, de "normál esetben" a processz id-k szabályosan, 1-el nőve fogják követni egymást. Tehát a parancsod esetén amit írtál, a $! értékét növeld meg kettővel (2db subshell nyílik a ctorrent előtt), és elvileg megkapod ctorrent pid-jét.
De mondom, ez nem biztos hogy oké lesz, csak most jobbat nem tudok :)

Használd a start-stop-daemon-t.
Kultúrált démon kezelésre (indítás/leállítás) ezt lehet használni.
Ott megadhatod hogy milyen feltételeknek feleljen
meg a leállítani kívánt processz.

pl.

-Check for processes that are instances of this executable (according to /proc/pid/exe ).
-Check whether a process has created the file pid-file.
-Check for processes owned by the user specified by username or uid.
-Check for processes with the name process-name (according to /proc/pid/stat).

stb...

Régebben volt egy bug a programban.
Nem állítota be a HOME és USER környezeti változókat.

Megoldása pl.:
USER=$(whoami)
HOME="/home/$(whoami)"

De lehet hogy azóta már kijavították.

A $! specialis pozicionalis parameter a legutoljara hatterben inditott procesz pidjet tartalmazza. Ezt elrakhatod valtozoba, vagy az inditas soran egy pid allomanyba is kiirhatod. Ezek utan mar tudhatod melyik pidet akarod leloni, amikor le akarod loni.

[quote:aa8620285e="Babszem"]Csak egy tipp, de mi volna, ha a megfelelő processz pidjét egy ps kimentéből greppelve szednéd össze?

HTH:
Babszem

pidof processzneve

Ha jól látom, FreeBSD-n nincs pidof parancs se :cry:.

A symlink-elős megoldás viszont tökéletes; köszi!

A process id-jet le tudod kerdezni a $$ kornyezeti valtozobol. Azt hiszem, innen mar minden megoldott...

Azert nem ennyire egyszeru a dolog - a $$ a shell pidje, nem a hatterbe kuldott parancse.