Tekintsük az alábbi bash kódrészletet:
cd "$tempdir"
ls -1 | (
for ((i=0; i<cores; i++)); do
pids[i]=0
done
count=0 # DEBUG
EXEC='pnmtopng'
while read; do
if [ -f "$REPLY" -a -r "$REPLY" ]; then
while :; do
found=0
for ((i=0; i<cores; i++)); do
if [ ${pids[i]} -eq 0 ]; then
found=1
break
# elif [ x"`ps -p${pids[i]} -o comm=`" != x"$EXEC" ]; then
elif ! pgrep -x "$EXEC" | grep -q "^${pids[i]}\$"; then
echo -e "pids[$i]=${pids[i]}\t:\t`ps -p${pids[i]} -o comm=`,\tEXEC=$EXEC"
pids[i]=0
found=1
break
fi
done
if [ $found -eq 1 ]; then
break
else
sleep 0.2
fi
done
"$EXEC" "$REPLY" >"$imagesdir/${REPLY%.*}.png" & pids[i]=$!
((count2+=suly2))
((count++)) # DEBUG
echo -ne "\r$[count1/max1+count2/max2] %\t\t"
fi
done
wait
echo -e "\r100 %\t\t"
echo "count=$count" # DEBUG
)
A kimenet itt látható.
Az elképzelés szerint egy filelistát pipe-olok egy subshell-be, ott inicializálok egy tömböt, amely annyi elemű, ahány magos a CPU, jelenleg ez 4. A tömbben a 0 azt jelenti, hogy ehhez nem tartozik futó process. Egy ciklusban végigmegyek a tömbön, ha találok benne 0-t, akkor kilépek. Ha nem 0 a pids[i], akkor megnézem, az adott pidhez tartozóan fut-e process, s annak neve az-e, amelyet én indítottam. Ha a név más, az csak úgy lehet, hogy időközben felszabadult ez a pid, s a kernel kiosztotta egy egészen más process-nek, ezért ellenőrzöm a nevet. Ha ez történt, bejegyzem, a tömbbe, hogy felszabadult a pid, s kilépek a ciklusból. Meg persze kiírok egy debug sort: a pids[i], a hozzá tartozó név - ez üres, ha nem került megint kiosztásra az adott pid a programomtól független folyamat által.
Ezután, ha mind a 4 pid valós, általam indított, élő programra hivatkozik, várok 200 ms-ot, majd pollingolom újra, befejezte-e valamelyik folyamat a működést. Amennyiben valamelyik pid már kihalt - found=1 -, úgy kilépek a látszólag végtelen while ciklusból egy break-kel, s indítom a megfelelő paraméterekkel a következő konverziót a háttérben, a pid-jét pedig tárolom a tömb felszabadult helyére: pids[i]=$! .
Mindösszesen ennyi lenne az egész, nem bonyolult. Ennek fényében a kimeneten látszik, hogy ahol a kettőspont utáni tabulátorokat követően csak vessző van, ott jól működik, ugyanakkor van, ahol pdf2png-t mond a ps -p${pids[i]} -o comm=
kimenete. Azt tudni kell, hogy a pdf2png a saját scriptem neve, tehát lényegében a basename "$0".
További furcsaság, hogy amikor meghülyül, a pidek 4-esével, 8-asával vagy 10-esével követik egymást szabályosan, s mindig ugyanazon i indexhez tartozóan.
Vagy valamit nagyon rosszul csinálok, vagy van egy bug a bash-ben, vagy a $! néha hülyeséget ad vissza, de akkor sem lehet, hogy 10-esével növekvő pid-del úgy gondolja, az a saját shell-em.
Nem értem. Ha valakinek van jó ötlete, jelezze!
- 8911 megtekintés
Hozzászólások
Lefuttattam a scriptedet, Ubuntu 10.10 (bash 4.1.5) alatt nem hibázott. Nem hiszem, hogy számít, de egy magom van, viszont a cores értéke 4 volt.
Én a $REPLY értékét is kiíratnám, hátha valami szemét kerül bele valahonnan.
- A hozzászóláshoz be kell jelentkezni
A dolog ott eshet hasra, amikor a háttérfolyamatot indítod el. A $! által visszaadott PID legelőször a pdf2png-t futtató shell gyereke (egy shell), ami ezután exec-eli a pnmtopng binárist. Más szóval a $! PID által jelölt processznek időben változik az image-e, és a neve is. Ezzel a változással fut versenyt a pdf2png script.
Ha a $! PID-ű processz image-e még a bash bináris, amikor a pgrep-pel rákeresel, akkor azt fogja hinni a script-ed, hogy az a PID már felszabadult (semelyik processzre sem igaz, hogy a megfelelő a PID-je és pnmtopng a neve). Ezután kiíratod a PID szerint a processz aktuális nevét. A pastebin-en található kimenet 99. sorában pl. azt látjuk, hogy eddigre már az exec lezajlott (abban a rövid időben, ami a pgrep-es ellenőrzés és a kiíratás között telt el), de pl. a 126-os sornál a child processz még mindig a bash image-et futtatta.
Jobban jársz, ha megnézed a GNU parallel-t.
Én egyébként a kérdéses feladatra megírtam a megoldást shell-ben, de iszonyatosan ronda lett, és például a ^C-vel történő megszakítás esetén nem küldi helyesen tovább a szignált az összes gyereknek (és unokának). Mondom, túl vastag. Mindenesetre a fő funkciót úgy fedi le, hogy a SIGCHLD-re rátesz egy handlert, ami minden egyes signal delivery-nél végignézi az egész PID tömböt, egyesével megpingelve (kill -0) az adott PID-et, és ha már nem létezik, akkor indít helyette egyet, egy új sort benyalva az stdin-ről (ha még nem értük el az stdin végét).
Itt a script lényege (public domain):
#!/bin/bash
set -e -C
declare PROGRAM_NAME
declare NUMBER_OF_WORKERS
declare WORKER_COMMAND
declare -x WORKER_ID
declare -a WORKER_PIDS
declare NO_MORE_JOBS
declare -x JOB_ID
declare -a JOB_ARGS
log0()
{
local MESSAGE=$1
echo "$PROGRAM_NAME: $MESSAGE" >&2
}
log()
{
local MESSAGE=$1
echo "$PROGRAM_NAME: $(date '+%s %Y-%m-%d %H:%M:%S %Z'): $MESSAGE" >&2
}
child_handler()
{
local CUR_WORKER_PID
local JOB_COMMAND
local JOB_ARG
local MESSAGE
for (( WORKER_ID=0; $WORKER_ID < $NUMBER_OF_WORKERS; ++WORKER_ID )); do
CUR_WORKER_PID=${WORKER_PIDS[$WORKER_ID]}
if [ -z "$CUR_WORKER_PID" ] || ! kill -n 0 $CUR_WORKER_PID 2>/dev/null
then
if [ $NO_MORE_JOBS -eq 0 ] && read -a JOB_ARGS; then
JOB_COMMAND=$WORKER_COMMAND
for JOB_ARG in "${JOB_ARGS[@]}"; do
JOB_COMMAND=$JOB_COMMAND\ \'${JOB_ARG//\'/\'\\\'\'}\'
done
JOB_COMMAND=$JOB_COMMAND\ \</dev/null
# Small window to leak a process.
eval "$JOB_COMMAND &"
WORKER_PIDS[$WORKER_ID]=$!
MESSAGE="spawned worker $WORKER_ID pid $! ($JOB_COMMAND)"
if [ ! -z "$CUR_WORKER_PID" ]; then
MESSAGE="$MESSAGE in place of pid $CUR_WORKER_PID"
fi
log "$MESSAGE"
JOB_ID=$(($JOB_ID + 1))
else
NO_MORE_JOBS=1
if [ ! -z "$CUR_WORKER_PID" ]; then
log "worker $WORKER_ID pid $CUR_WORKER_PID terminated"
WORKER_PIDS[$WORKER_ID]=""
fi
fi
fi
done
}
PROGRAM_NAME=$(basename "$0")
if [ $# -lt 2 ]; then
log0 "Usage: $PROGRAM_NAME NUM_WORKERS WORKER_COMMAND ARG_1 ARG_2 ..."
log0 "Invoke WORKER_COMMAND with ARGs for each command line read from stdin."
log0 "Run at most NUM_WORKERS instances in parallel."
log0 "Exported environment variables for WORKER_COMMAND are:"
log0 " JOB_ID: index of command line read from stdin (zero based),"
log0 " WORKER_ID: integer instance identifier in [0, NUM_WORKERS)."
exit 1
fi
NUMBER_OF_WORKERS=$1
if ! [ "$NUMBER_OF_WORKERS" -gt 0 ]; then
log0 "NUM-WORKERS must be positive"
exit 1
fi
shift
while [ $# -gt 0 ]; do
WORKER_COMMAND=$WORKER_COMMAND\ \'${1//\'/\'\\\'\'}\'
shift
done
set +e -m
NO_MORE_JOBS=0
JOB_ID=0
trap child_handler SIGCHLD
true &
wait
Kiegészítés:
- A handler futása alatt a szignál blokkolva van. Amíg fut a handler, további child processz-ek is befejeződhetnek. Ezt vagy észrevesszük már a handler-ben, vagy nem. Mindenesetre ilyenkor a signal ismét pending-gé válik, és amint véget ér a handler, azonnal kézbesítődik a szignál újra. Ilyenkor az összes lefutott gyereket kezelni kell, nem csak egyet közülük. Ezért van a handler-ben ciklus.
- A sok escape-elés arra való, hogy a bemeneti file-ba soronként argumentumoknak egy listáját lehessen beírni. A whitespace az argumentum-elválasztó, amit backslash-sel lehet escape-elni. Egy argumentum tartalmazhat idézőjelet ill. aposztrofot is.
- A hozzászóláshoz be kell jelentkezni
Köszönöm a segítséged! A magyarázat logikus, s valóban indokolja a működést, illetve annak hiányát. :) Nem tudtam, hogyan indít a shell folyamatot a háttérben. Valamiért azt gondoltam, hogy az illető, általam indított nevű lesz az új process, amelynek a PID-jét visszakapom a $!-ben. Erre a tranziens folyamatra nem gondoltam, nem tudtam róla, s közben kihullott az összes hajam. Látszik a comment-elt sorból, hogy egy gyorsabb metódussal is megpróbáltam megvizsgálni az adott process nevét, az volt az eredeti - nyilván a pgrep kimenetét grep-be pipe-olva szűrni lassabb -, de már az is hasonlóképpen többnyire működött, ám sokszor nem.
Azt ugyan nem írtam, de a hibás működés egyfelől azért zavart, mert az nagyon nincs rendjén, ha valami nem úgy működik, ahogy elképzelem, s nem értem, mi a baja, másfelől meg így 4-nél lényegesen több példányban indítja adott esetben a konverziót, amely forkbombaként tud működni.
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ezt általában úgy csináljuk, hogy megszámoljuk hogy hány (pdf2png) processz fut, és ha kevés, akkor indítunk még párat, ha elég, akkor várunk kicsit. Persze ez nem túl pontos, de általában tökéletesen megfelelő megoldás.
A ctrl-c-re általában ez is rosszul szokott reagálni, én úgy állítom le, hogy van egy file, aminek a meglétét ellenőrzi, és ha az létezik, akkor kilép minden alprocessz.
Illetve másik gépen, másik scritben a load értékét figyelem, annak függvényében indítok újabb processzt.
- A hozzászóláshoz be kell jelentkezni
A load figyelése hasznos.
- A hozzászóláshoz be kell jelentkezni
Jaja, en is kuzdottem ilyennel. De vagy kotegelve inditom, vagy pedig jon a mokolas a processzek szamolgatasaval.
Esetleg mas, fejlettebb nyelvben megvalositott felugyeloprogram lehetne meg a megoldas.
- A hozzászóláshoz be kell jelentkezni
Igen, ez a műszakilag ugyan nem korrekt, nem precíz, ám gyakorlatilag jó megoldás. Ennél kicsit szofisztikáltabb megfejtésre vágyom.
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Sajnos tőlem csak ennyi telik... hehe.
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
subscribe
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni
Nem lesz túlságosan konstruktív, de leírom: én, amikor ilyen bonyolultságú feladat kerül elém, tuti nem shell scriptben erőlködök. Ennél jóval egyszerűbb dolgokra is sokkal hamarébb előveszem a perlt.
- A hozzászóláshoz be kell jelentkezni
+1
Legutóbb, amikor ilyesmire volt szükségem, a Proc::Queue modult használtam. Van neki egy system_back nevű parancsa, amellyel a háttérben indíthatók külső parancsok, és a modul felügyeli, hogy mindig pont annyi fusson egyszerre, amennyi kell.
- A hozzászóláshoz be kell jelentkezni
subscribe
- A hozzászóláshoz be kell jelentkezni
.
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni
Most értem haza, nem voltam gépközelben, olvasom a válaszokat rögvest... :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Itt folytatom, nem akartam túl hosszú hozzászólást. :)
A scriptemnek van egy első fele, hasonlóképpen párhuzamosítani kell. Az egész annyit csinál, hogy egy pdf file-t oldalanként png képfile-okba renderel, továbbá a pdf file-ból kiszedi az abba eredetileg képként berakott objektumokat. Mivel 600 dpi esetén egy 56 oldalas, képekkel teletűzdelt doksival ~18 perc alatt végzett, úgy éreztem, jó volna kihasználni a 4 magos CPU-t, hiszen ezért van. Így a futásidőt sikerült ~5 percre leszorítani.
Amíg volt a scriptemben egy bug, elindult 56 példányban a konverzió, felfalta a soványka 2 GB RAM-omat, megevett mellé 7 GB swap-et, az egér kurzort már nem bírtam megmozdítani, az óra, amelynek másodpercenként kellett volna frissülnie, úgy 5-10 percenként frissült, hasonlóképpen a conky, illetve a top is. Mondjuk érthető. :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Barátkozom ezzel a parallel nevű szerszámmal...
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Nagyon nagy találmány ez a parallel, működik. Köszönet a tippért! :)
Szerk.: Nem magamnak akartam válaszolni, csak így sikerült. Álmos vagyok már...
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Az hogyan lehetséges, hogy pipe-olok valamit a tee-nek, s amit ír file-t, az menet közben hízik, majd a végén összemegy?
Konkrétabban a parallel stderr-re írott kimenetéből akartam yad-dal progress bar-t csinálni vázlatosan így:
seq $p | parallel --eta paraméterek 2>&1 | tee "$HOME/debug" |\
awk 'script' | yad --progress --auto-close --egyebek
A debug file működés közben 13kB+ is lesz, aztán a végén összemegy 4.4 kB-ra. Ez hogyan van? Ami egyszer átment a csövön, annak még utána lehet nyúlni? Már megint nem értek valamit...
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ez a jelenség akkor szokott előjönni, amikor felülírod a fájlt. Ha jól emlékszem a tee alapból újrakezdi a fáljt, a "-a" -val appendel, ha a parallel valahogyan többször indul el, akkor valószínűleg az utoljára elindult szál outputja (ami persze a "maradékot" kapja és így rövidebb) marad meg csak.
Vagy máshol írod felül a debug fájlt.
Vagy az lehet - ezt majd megerősíti vagy -cáfolja az, aki ért a unix programozáshoz -, hogy parallel minden szálnak saját stdout-ot (és gondolom stderr-t is) nyit. Ha egyáltalán lehet ilyet.
- A hozzászóláshoz be kell jelentkezni
vagy ez: pexec (ill kis reklam :] de van debian/ubuntu alatt is, `apt-get install pexec`)
- A hozzászóláshoz be kell jelentkezni
Ha keresek a pexec stringre, Fedora a parallel-t ajánlja. :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
tedd fel forrasbol, egyszeru" az is ;)
- A hozzászóláshoz be kell jelentkezni
Régebben fordítgattam forrásból, most viszont törexem arra, hogy lehetőleg mindent a disztribúció eszköztárából oldjak meg. Volt idő, amikor vanilla kernelt fordítottam, meg egyéb finomságok. Biztos öregszem, de ez kevéssé vonz már.
A parallel működik, csak egyelőre nem sikeredett kinyernem a yad számára az infót, hogy progress bar-t csináljak. Ha már látom, pontosan mit is tartalmaz a file, akkor megoldom.
Van vész forgatókönyvem is. Nézem egy háttérben elindított script-ben, mennyi file jött létre, tudom, mennyire számítok, a kettő hányadosa, amit a yad-nak kell pipe-olni. Tehát mindenképp megoldom, csak a kisebb gányolás irányába mennék. :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
A legjobb az, amikor a debugban lévő hiba vezet félre. Igen, a tee -a jobb megfejtés volt. Ugye a tee csak debug célokat szolgált. Ettől eltekintve egyetlen hiba volt benne: kihagytam az awk scriptből az fflush()
hívást. Itt nem elég, hogy a végén legyen eredmény, rekordonként kell, hiszen a progress bar valós idejű. Az nem mutat jól, hogy a folyamat ideje alatt 0%-on áll, majd a végén pár ms alatt felszalad 100%-ra. :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Azért még kérdezek. :)
Hogyan lehet megtudni, hogy egy pipe-ban mi a pid-je az egyes process-eknek? Mondom, mi a probléma. Használom ezt a yad nevű jószágot, de az a sanda gyanúm, hogy bugos, szeretném megkerülni a problémát. Az alábbi szerkezetű az adott részlet:
(itt vannak dolgok subshell-ben) | yad --multi-progress
Fontos tudni, hogy a --auto-close kapcsoló csak a --progress esetén működik. A gond az, hogy hiába hal ki a subshell, szűnik meg a pipe bal oldala, a yad éli világát, s bambán néz. Én meg azt szeretném, hogy például a subshell utolsó utasításával kinyiffantanám a yad-ot valahogy ekképpen:
(itt vannak dolgok; kill $PID_YAD) | yad --multi-progress
Gondoltam használni a bash coproc dolgát. Ezzel is az a baj, hogy a yad nem hajlandó meghalni, elárvult process marad. Az alábbi kód - egy sorban írtam, mert nem volt kedvem file-ba írni - és eredménye:
coproc { yad --multi-progress --bar=alma --bar=korte; };
for ((i=0; i<=100; i+=5)); do echo -e "1:$i\n2:$[i/2]";
[ $i -eq 80 ] && { echo "COPROC_PID=$COPROC_PID"; pgrep -lx yad; pgrep -lx coproc; } >&2;
sleep 0.2; done >&${COPROC[1]};
pgrep -lx yad; pgrep -lx coproc
[1] 27652
COPROC_PID=27652
27654 yad
27654 yad
Ugye itt megint az a baj, hogy a yad pid-jét nem tudom. Hogyan lehet megtudi?
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Hogyan lehet megtudni, hogy egy pipe-ban mi a pid-je az egyes process-eknek?
Egy példával szemléltetve, valahogy így:
$ yes | cat > /dev/null
$ lsof | grep -E "^(yes|cat)" | grep pipe
yes 6098 user 1w FIFO 0,8 0t0 358030 pipe
cat 6099 user 0r FIFO 0,8 0t0 358030 pipe
$ readlink /proc/6098/fd/1
pipe:[358030]
$ readlink /proc/6099/fd/0
pipe:[358030]
- A hozzászóláshoz be kell jelentkezni
Köszönöm, ez remek, már látom, hogy lesz megoldás, de előbb alszom egyet. :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Illetve... mi van, ha több ilyen pipe van? Mert a killal yad eddig is "megoldás" lehetett volna. Olyasmit keresek, ami pontosan azonosítja a process-t, nem vaktában akarok lövöldözni rájuk. Bár, ha a yes egy subshell-ben van, akkor az ő szülőjének pid-je megtudható, az meg utána kideríthető az lsof-fal, hogy ki van a cső másik oldalán. Ha jól gondolom. Holnap kifaragom.
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ha tudod a shell pid-jét (miért ne tudhatnád), akkor a
$ pstree -p SHELL_PID
$ pstree -p | less
közül, amelyik szimpatikusabb az segít neked nagy valószínűséggel.
Ezután a megfelelő gyerek PID-jére keresel lsof-ban.
lsof-ból megtudod a pipe azonosítóját.
Ezután arra az azonosítóra keresel lsof-ban és megvan minden amit akartál, de már a pstree-ből látszani fog minden amúgy, valsz lsof nem is kell.
- A hozzászóláshoz be kell jelentkezni
Természetesen nem vizuálisan szeretném látni, hanem a scriptben végezni azzal a nyamvadt yad-dal, amely nem hajlandó kipusztulni, ha a szülője meghal. Embernél ez érthető, process-től viszont nem ezt várom. :)
Szóval lsof lesz ebből, de manualt olvasok, mert szűkíteni szeretném a kört. A greppel történő szűrés szerintem elég lassú lehet, mert opciók nélkül az lsof kimenete igen terjedelmes, hiszen mindent visszaad. Mindenesetre már látom az alagút végét, köszönöm.
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
+subscribe
* Én egy indián vagyok. Minden indián hazudik.
- A hozzászóláshoz be kell jelentkezni
Gondoltam, ideírom a megfejtést, de épp bénázok. Parancssorban működik, a scriptben már nem. Vagy elírtam valamit, vagy nem tudom. Most debugolok...
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Megvan a nyomorult! :) Szóval azon csúsztam el, hogy a $BASHPID nevű változó nagyon helyesen az aktuális shell pid-jét adja vissza. Ez viszont egy pipe esetében nem az őt futtató subshell pid-je. Mindjárt részletezem.
Tehát a feladat így nézett ki. A gui változó azt mondja meg, hogy legyen-e grafikus felület, vagy terminálon futkorásszon.
if [ $gui -eq 1 ]; then
output='yad --title="$selfname" --width=$width --multi-progress --bar="${label[0]}" --bar="${label[1]}"'
else
output='cat'
fi
...
(
itt előállítjuk a progressbar vezérlését vagy a terminálra írandókat
) | eval "$output"
A gond ugye az volt, hogy a végén az a yad, amely az eval-lal értékelődik ki, nem lép ki, s valahogy a pipe másik oldaláról szeretném lelőni, amikor elérte a zárójelben lévő rész a subshell-ben a működésének végét, s így a 100%-ot jelezte a yad-nak, amit az megjelenít.
A megoldás alant:
pipepid=`cat<<'EOF'
BEGIN {
pipe = -1;
}
/pipe$/ {
if (pipe == -1) {
if ($2 == bashpid) {
pipe = $8;
FNR = 1;
}
} else {
if ($8 == pipe && $1 == procname) print $2;
}
}
EOF`
if [ $gui -eq 1 ]; then
output='yad --title="$selfname" --width=$width --multi-progress --bar="${label[0]}" --bar="${label[1]}"'
else
output='cat'
fi
...
(
itt fut a program, valamint előállítja a yad-nak küldendő %-os értékeket stdout-ra
bashpid=$BASHPID
kill `lsof -u "$USER" -U | awk -v bashpid=$bashpid -v procname='yad' "$pipepid"`
) | eval "$output"
Fontos momentum, hogy nem írható az awk -v bashpid=$BASHPID, mert ott éppen más az értéke. Nekünk annak a subshell-nek kell a pid-je, amelyik a zárójelen belül van. Így aztán kell a bashpid=$BASHPID, majd ezt a változót adjuk át az awk-nak.
A pipepid awk script először megkeresi az lsof kimenetéből, hogy a subshell-ünk melyik pipe-ba ír, majd kikeresi - szintén elölről -, hogy ehhez a pipe-hoz melyik procname nevű process - ez ugye a keresett yad - csatlakozik, majd ezzel a pid-del küldünk SIGTERM-et a yad-nak. Erre már, ha unott képpel ugyan, de kegyeskedik kilépni. :)
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Ez mindez azért van, mert az --auto-close nem működik?
- A hozzászóláshoz be kell jelentkezni
Igen. Különben van benne egy bug, szánom-bánom bűnömet. Nem vettem észre, mert működik, a hiba viszont elvi. Természetesen az awk-nak nem lehet azt mondani, hogy újra az elejéről olvassa a record-okat. Az az FNR=1 marhaság. Csak azért működik, mert a pid-ek olyan sorrendben jönnek az lsof kimenetében, hogy miután megtaláltam a pipe azonosítóját, utána jön az a process, amit keresek. Mindjárt kiötlök valami elvileg is jó megoldást. Így jár az ember, ha hamarabb kommentel, mint gondolkodik. :-/
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Akkor írom a javítást. Ez már nem csak gyakorlatilag, de elvileg is jó:
pipeawk=`cat<<'EOF'
/pipe$/ {
if ($2 == bashpid) {
print $8;
exit 0;
}
}
EOF`
pipepidawk=`cat<<'EOF'
/pipe$/ {
if ($8 == pipe && $1 == procname) print $2;
}
EOF`
if [ $gui -eq 1 ]; then
output='yad --title="$selfname" --width=$width --multi-progress --bar="${label[0]}" --bar="${label[1]}"'
else
output='cat'
fi
...
(
itt végzi, amit kell, s előállítja a progressbar vezérlési infót
if [ $gui -eq 1 ]; then
bashpid=$BASHPID
lsoftext="`lsof -u "$USER" -U`"
pipe=`awk -v bashpid=$bashpid "$pipeawk" <<<"$lsoftext"`
kill `awk -v pipe=$pipe -v procname='yad' "$pipepidawk" <<<"$lsoftext"`
fi
) | eval "$output"
A javítást azért írtam, mert fentebb ostobaság volt, ne az maradjon meg.
tr [:lower:] [:upper:] <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
+sc
- A hozzászóláshoz be kell jelentkezni