Adott ez a kicsi szkriptecske:
#!/bin/bash
trap "stdbuf -o0 echo xyz" WINCH
while true; do
echo $RANDOM
sleep 5
done
Miert lehet az hogy a signal kesik es csak akkor hajtja vegre a shell es/vagy a rendszer amikor aktivitas van a terminalon? Az internetekben csak ezt a `stdbuf` dolgot talaltam igy hirtelen, ami kapcsolodo lehet - de nem az a nyitja. Buffereltlenul meg bufferelten is ugyanugy kesik. Rendszer: debian/stretch.
- 1271 megtekintés
Hozzászólások
"amikor aktivitas van a terminalon" – bármit is értesz ezalatt pontosan, ahhoz semmi köze. A stdbuf meg valóban irreleváns.
Addig nem fut le a trap (talán rá se néz a szignálra a shell), amíg az előtérben indított külső parancs (esetünkben "sleep 5") fut. Majd ha az lefutott, és ismét dolga akad a shellnek, majd akkor foglalkozik az ablakméret szignállal.
- A hozzászóláshoz be kell jelentkezni
Na jo, de ha azt irom oda meg az elejebe, hogy:
trap "stdbuf -o0 echo abc" INT
akkor az miert fut le azonnal ha ctrl+c-zek egyet? szignal-szignal, nem?
- A hozzászóláshoz be kell jelentkezni
A WINCH szignállal a sleep nem törődik. A shell igen, kezeli amikor ráér.
Az INT szignállal viszont törődik a shell és a sleep is, a sleep kilép. És ekkor a shell is rögtön kezelni tudja a saját INT-jét. Cseréld ki a sleep-et egy olyan parancsra, amelyik nem lép ki INT-re (például bc), hiába ütöd a Ctrl+C-t, nem fog megjelenni az "abc".
- A hozzászóláshoz be kell jelentkezni
1. a Ctrl-C nyomása interaktív shell-ben nem egészen ugyanaz mint simán egy SIGINT ellövése valahonnan.
az interaktív shell ugye új pgid-del indítja el az egy parancssorban megadott parancsot vagy parancsokat (compound command), és Ctrl-C-nél az egész process groupra küld SIGINTet.
2. mellékesen
stdbuf echo
helyett
/bin/echo
mint külső parancs is kielégíti az stdout flush-olást.
~~~~~~~~
deb http://deb.uucp.hu/ wheezy yazzy repack
- A hozzászóláshoz be kell jelentkezni
> stdbuf echo helyett /bin/echo mint külső parancs is kielégíti az stdout flush-olást.
A beépített echo is. A bash flush-ol minden beépített parancsa után.
- A hozzászóláshoz be kell jelentkezni
biztos? én 4.2.37(1)-gyel nem ezt tapasztalom.
ugye a külső echo se flush-ol explicit, viszont zárja a pipe-ot és ezért az OS flush-ol.
~~~~~~~~
deb http://deb.uucp.hu/ wheezy yazzy repack
- A hozzászóláshoz be kell jelentkezni
> biztos?
Eléggé. Nemrég volt róla szó a bash levlistán. Így alakult történelmileg, és így tud csak a viselkedés konzisztens lenni külső programok illetve beépített parancsok között.
> én 4.2.37(1)-gyel nem ezt tapasztalom.
Hogy néz ki a konkrét progid, és hogy viselkedik?
> ugye a külső echo se flush-ol explicit, viszont zárja a pipe-ot és ezért az OS flush-ol.
Kavarsz.
Mit értesz OS alatt? A kernel szintjén a flusholás nem létező koncepció, a kernel szintjén csak írni lehet. Amit kiírtál, azt kiírtad pont akkor. Amit nem, az nincs.
A pufferelést és flusholást a libc vezeti be egy felette lévő stdio rétegként. A külső echo, ha stdio-t használ, tehát pufferel (amiben nem vagyok biztos, de jó eséllyel igen), akkor valószínűleg kilépéskor is flushol, mivel a felső szintű fájlkezelő rutinok a libc-ben így vannak megírva, tehát nem ragad benn adat. De tudtommal nem zárja a fájlleírót (majd a kernel, amikor a processz kilép, kénytelen lesz), és nem is érdekli hogy pipe-ba megy-e. Sőt, magát a pipe-ot mint objektumot, melynek akár más író processze is lehet, nem zárja (bármit is értsél ez alatt) explicit módon, nem is tudná.
- A hozzászóláshoz be kell jelentkezni
valóban megtévedtem azzal, hogy a flush nem syscall, hanem libc szintű függvény.
> nem zárja a fájlleírót
> majd a kernel, amikor a processz kilép
a külső echo processz futása végén van
close(1)
syscall a
exit_group(0)
előtt. erre gondoltam. vagy a program hívta explicit vagy a kernel a processz kilépése folyományán - ahogy te is mondod -, a lényeg számomra az hogy így külső echo-val egyből megjelenik a pipe másik végén az adat. míg megfigyelésem szerint belső echóval nem. de lehet hogy rosszul figyeltem meg, örülnék ha a végére tudnánk járni.
az én esetemben volt egy processz, ami csinált egy pipe-ot, forkolt, rá dup()-olta a pipe író végét az stdout-ra, az olvasó végét meg az stdin-re a szokott módon. aztán execelt egy bash szkriptet. a szkript normálisan built-in echo-val írt de nem egész sorokat (pl:
echo -n processing .; sleep 60; echo -n .; sleep 60; echo -n .
).
Ekkor azt tapasztaltam, hogy a parent processz csak komplett sorokat olvas ki, noha alacsony szintű sima read()-del olvasott 1 byte-onként nem blokkoló módon (fcntl F_SETFL O_NONBLOCK, read(1, buffer, 1)).
Míg ha a szkriptben külső echót használtam, akkor a félsorokat is megkapta.
Ebből arra következtettem, hogy a built-in echo kimenete valahol bufferelve van.
Korábban azt gondoltam, hogy mivel a belső/külső echo ugyanarra az fd-re írnak és a buffer beállítás az fd-re vonatkozna, nyilván sorbufferelés van és egy alprocessz meghívásával implicit kicsikarhatok belőle egy flush-t.
Node - miképp megvilágítottad – a bufferbeállítás a file handlerre vonatkozik és processzenként más-más lehet.
Ennek ellenére továbbra se tiszta számomra, hogy ha a bash minden egyes builtin echo után üríti a buffert, akkor miért nem látom az adatot addig amíg nem jön egy "\n".
~~~~~~~~
deb http://deb.uucp.hu/ wheezy yazzy repack
- A hozzászóláshoz be kell jelentkezni
{ echo -n processing .; sleep 5; echo -n .; sleep 5; echo -n .; } | cat
( echo -n processing .; sleep 5; echo -n .; sleep 5; echo -n . ) | cat
Mindkettő azonnal írja nekem a pöttyöket, tehát a cicus megkapja egyenként azokat.
Tudsz mutatni kódot, ami reprodukálja az általad említett, pufferelt jelenséget?
- A hozzászóláshoz be kell jelentkezni
nem tudom reprodukálni az a működést amire emlékeztem, ezért kénytelen vagyok elfogadni hogy a belső echo is flush-ol.
egyébként ebben a snippetben attól hogy más bracketinget használsz, letiltja a builtin parancsokat?
~~~~~~~~
deb http://deb.uucp.hu/ wheezy yazzy repack
- A hozzászóláshoz be kell jelentkezni
Nem; a flusholás kérdése tekintetében valóban a két parancs azonos kell hogy legyen, így tulajdonképpen fölösleges volt mindkettőt leírnom.
- A hozzászóláshoz be kell jelentkezni
> attól hogy más bracketinget használsz, letiltja a builtin parancsokat?
A { ... ; } forma esetén a shell nem hoz létre egy alprocessz a a zárójelek közötti ... parancsok végrehajtásához, míg a ( ... ) forma esetén igen.
=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
- A hozzászóláshoz be kell jelentkezni
ezt vágom, de a builtin/external echo tekintetében nem különbözik. nem?
~~~~~~~~
deb http://deb.uucp.hu/ wheezy yazzy repack
- A hozzászóláshoz be kell jelentkezni
Tippre nem, de sose néztem utána
=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
- A hozzászóláshoz be kell jelentkezni
a bash csak akkor dogozza fel a szignálokat, amikor nem futtat épp külső parancsot.
tehát szerintem bevárja a sleep-et.
én így szoktam elkerülni:
sleep()
{
local sleep_pid exit_status
command sleep "$@" &
sleep_pid=$!
while ! wait $pid; do true; done
return $exit_status
}
bármilyen kód...
a 'while' a 'wait' köré azért kell, mert megszakad a wait, amikor szignált kap, hogy feldolgozza a szignált, de aztán nem lép vissza magától a 'wait', tehát addig waitelek újra meg újra amíg lehet.
EDIT
while kill -0 $sleep_pid; do wait $sleep_pid; exit_status=$?; done
csere
while ! wait $pid; do true; done
~~~~~~~~
deb http://deb.uucp.hu/ wheezy yazzy repack
- A hozzászóláshoz be kell jelentkezni