bash script pipe probléma

Fórumok

Adott egy egyszerű script, amiben van egy jelszógenerálás. Minden más rész lényegtelen, ez az egy sor magában a probléma.

tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 10 | head -n 1

Ez egyébként tökéletesen működik, kivéve amikor spacewalk-ból (egy management program, amivel többek között lehet scripteket kiküldeni központilag a szerverekre) küldöm ki a scriptet egy hostra. Ekkor az a jelenség, hogy a head megáll, de nem zárja vissza a csövet dominó szerűen, hanem "kinyílik" a vége, és elkezd kifele ömleni a szar, a fold meg a tr felmegy 100-100% CPU-ra, és a végtelenbe mennek, amíg el nem timeout a script, vagy én ki nem lövöm.

Tehát gyakorlatilag az történik, mintha a head nélkül indítanám, és a tr meg a fold folyamatosan adják a 10 karakteres stringeket. Valójában az történik, hogy a head "megáll" 1 után, ahogy kell, a script kimenete egy darab sor, de a head hiába áll meg, a tr és a fold tovább megy.

Remélem érhetően sikerült leírni. :)

A kérdésem: Miért? Milyen környezeti változó, vagy beállítás okozza? Halvány lila fogalmam sincs... Többször néztem, semmi ötletem.

Hozzászólások

Esetleg dd-vel:
dd if=/dev/urandom count=1 bs=2048 2>/dev/null | tr ...
Persze, nem lehetetlen, hogy a tr révén ez üres stringet eredményez, de azért nem valószínű.
--
eutlantis

Így "jó". Ugyanaz történik egyébként, azaz a head megáll, a többi meg megy tovább, csak azért nem végtelen, mert a count és a bs miatt véges a dd. Viszont jó lenne a probléma okát megtalálni, mert ez azért elég kokány. Ráadásul mi van, ha valami csuda folytán a 2048 bájtba nincs 10 a kritériumoknak megfelelő karakter? :)
--
"Sose a gép a hülye."

Tehát az utolsó pipe-pal van a gondod. Vélelmezem, hogy a szpészvók :) azt a beviteli mezót szépen megrágja, mielőtt odaküldi a kliensnek, és a csövet nem szereti benne (lehet, hogy nem véletlen a beviteli mező "remote script" elnevezése, "remote command(line)" ellenében). Ilyesmit simán el tudok képzelni (csak előre ott lévő script futtatható, ad-hoc összedrótozott parancssor nem), kifejezetten biztonsági/stabilitási okokból is.

Ha semmiképp sem akarsz scriptet írni/előre leküldeni, pwgen-t sem akarsz mindenhova felpakolni, akkor (mivel kíváncsi voltam, kigugliztam) Perl-ben van egy soros megoldás rá :) Neked elég a 0..pop helyett a 0..9, és nem kell a paraméter se a végére.

Nem remote command, remote script. Így néz ki: https://snag.gy/hoZW3R.jpg
És amit ide beírsz/bemásolsz script, az így ahogy van átkerül a célgépre /var/tmp/akarmi.sh néven, és úgy fut.

Köszi a perlt, de ettől függetlenül érdekelne hogy miért nem úgy működik a pipe, ahogy várom, és a végére akarok járni.
--
"Sose a gép a hülye."

Hogy mi lehet a probléma oka/megoldása, azt passzolom, workaroundként javasolnám a pwgen használatát: pwgen -s 10 1

Igen, csak pwgen nincs minden gépen, míg urandom meg az alap tool-ok vannak. :)
Van 'pwmake', de ennek meg csak hosszt lehet adni, azt nem, hogy mi legyen a jelszóba, és tesz bele minden spec karaktert is. Ma rögtön bele is futottam egy problémába emiatt, ugyanis például
passwd --stdin userke << EOF
$PASS
$PASS
EOF
szar, ha $ is generált a jelszóba. :)
--
"Sose a gép a hülye."

törölve teszteltem amit írtam és nem ok.

tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c10

Így esetleg ?

Így sem. Ezzel is az van, hogy a head megáll, a tr meg megy tovább.
Igazából a pipe-nak az összekötésével van baj, ez tuti. Mert az eredeti meg ez volt:
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1
Nem annyira szép, de így logikus, és egy vak is látja a lépéseket, azt jött egy kósza ötlet, hogy lehet hogy túl sok a pipe, és ebből lett az indító hsz-ben írt, ami ugyanezt produkálja. De igazából tök mindegy, mert egyetlen pipe is produkálja.

--
"Sose a gép a hülye."

Ha nincs egy sem, akkor mi a szitu? Matematikailag sem jön ki a dolog (gondold alaposan át a visszatevéses mintavételt és környékét).
Amit lehet tenni, az az, hogy a random értékek közül a nem megfelelőket valamilyen matekozással (MSB levágása, bitek jobbra tolása átvitel nélkül, stb.) megfelelővé tenni - ekkor elég 10 elemet kivenni.

Ugyanez a script másképp futtatva azon az illető távoli gépen?


ssh user@host '/path/whatnot.sh'
ssh user@host '/bin/bash /path/whatnot.sh'
ssh user@host '/bin/bash -xv /path/whatnot.sh'
...

Ha én futtatom akárhogy, userként, rootként, akkor jó.
Teljesen biztos, hogy a környezettel, valami set beállítással vagy ilyesmivel van probléma, amit a spacewalk megcsinál, vagy épp nem csinál, vagy másképp csinál. Csak gőzöm sincs, hogy mi lehet az.
--
"Sose a gép a hülye."

Egy par otlet, hatha meg nem probaltad oket:

- Debugolj a scriptbol, irasd ki a kornyzeti valtozokat es nezd meg mi ter el a te futattasi kornyezetedtol.
- Nezd meg milyen user futtatja a scriptet, futtasd te is azzal
- Futtasd kezzel ugyanazt a scriptet, ugyanazokkal a jogokkal amit o felmasol a gepekre
- strace

"kivéve amikor spacewalk-ból ... küldöm ki a scriptet egy hostra. Ekkor az a jelenség, hogy a head megáll, de nem zárja vissza a csövet dominó szerűen"

Azt aruld mar el hogy jon ide ahhoz hogy atkuldesz egy scriptet az adott gepre az hogy ilyen direkt parancsokat probalsz tavolrol futtatni?
Avagy hogy probalod a spacewalk-nak beadni ezt a parancs futtatast tavolrol?
Miert nem masolod at scriptet es azt futtatod tavoli gepen vagy generalod le localban a random jelszot es adod at azt valtozokent a tavoli gepnek?

Hát, látszik hogy sose kezeltél még sok gépet, meg nem automatizáltál.
1. Mert ebben az esetben nem megy. Nem tudom mi miatt, ezért írtam ide. Megérzésem szerint valami olyasmi lehet, hogy mivel a spacewalk elkapja a script minden kimenetét, valamit állít pl. az outputon, megduplikálja vagy fingom sincs, hogy menjen egy temp kimeneti fájlba (is), amit az agent a script futása után visszaküld a szervernek, hogy ott is látni lehessen az eredményt. És emiatt nem úgy működik a pipe, ahogy várnád... Nem tudom, találgatok.
2. Van a spacewalk-nak erre egy input mezője, mint remote script.
3. Mert a f*szom se akarja 30-60-80 gépre kopizgatni kézzel scriptet adott esetben, meg utána futtatgatni, meg megnézni hogy miért nem lett jó. Erre való a management. Plusz nem is akarom tudni a jelszót, de nincs is ilyen lehetőségem. Jelen esetben amit legenerált, azt beállítja a usernek, és elküldi SMS-ben.
--
"Sose a gép a hülye."

De kezeltem mar es pont az ilyen pipe-ok, fajlba iranyitasok, kulonfele idezojelek es tarsai okozta szivasok miatt egyszerubb kerulni a direkt shell parancsokat.
Azert van/lehet irni modult ami letrehozza a random jelszot, vagy fogni egy erre szolgalo pwgen/mkpasswd/stb parancsot amit ha kell automataval feltelepited elotte a gepre.
De ha konnyebb a shell script akkor azt felmasoltatni automatizmussal es tavoli gepeken futtatni.
Vagy localban generalni jelszavakat, ahelyett hogy tavoli gepeken csinalnad es ezert szivsz a kulonfele pipe-okkal.

Nezd meg hogy mi a kulonbseg a


ssh valaki@valahova seq 10 | head -n 5

illetve a


ssh valaki@valahova 'seq 10 | head -n 5'

kozott. Elsore ugyanazt csinalja mind a ketto latszolag, de ezutobbi a remote host-on fut vegig, ezelobbi meg felig itt, felig meg ott. Vsz hasonlo lehet a spacewalk-nal is, csak azt nem ismerem :)

Igen értem, de ez nem ssh-val csinálja a commandok futtatását, és nem is egy commandot visz át, hanem a scriptet, ahogy én megírtam.
Amit írtam egysoros, az nem az egész, csak az a rész, ahol a probléma kijön. A script usert kreál, jelszót és csoportot állít neki, ssh kulcsot generál, berakja a megfelelő helyre, rsa kulcsot mailozza a usernek, a jelszót pedig elküldi sms-ben.
--
"Sose a gép a hülye."

Van egy bash script, ami jó, de a Spacewalk elcseszi. Miért a scriptet akarod megjavítani? Esetleg miért nem a stabil és támogatott Satellite-ot használod? Akkor a support talán megoldaná a problémádat. Tudom, pénzbe kerül, de:

„Mert a f*szom se akarja 30-60-80 gépre kopizgatni kézzel scriptet adott esetben”

Ebből nem úgy tűnik, hogy egy hobbi projektről van szó. Nem lehet betervezni a management szoftver árát is projektbe?

Helyesen: Van egy bash script, ami adott körülmények között jó. Van amiben meg nem, és szeretném az okát megtudni. Lehet, hogy nem tudok rajta változtatni, mert a spacewalk így csinálja és kész, de ettől még érdekel.
Nem egy projekt, sok kicsi.
Jelen scriptet nem akarom 80 gépen letolni, csak kb. 15-re kellett, csak példa okán írtam (mert van olyan), hogy valamit mindegyiken meg akarok csinálni.
--
"Sose a gép a hülye."

Annyit azért megjegyeznék, hogy láttam már olyat, hogy a /bin/sh másként működött interaktívan hívva, mint script elején she-bang-ként. Linuxon. Szóval amit zeller mond, abban is lehet valami, egyelőre mindenki csak tapogatózik.

=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?

Amikor a head eleget olvasott, bezárja az stdint, ekkor a pipe másik oldalán az író kap egy SIGPIPE-ot. A pipe másik oldalán vagy a shell, vagy az előző parancs van, ezt nem tudom. Úgy néz ki, hogy ezt a signalt valami megeszi nálad. Erre keresgélj.

Fasza, ezek szerint ez a skywalker beállítja a sigpipe-ot IGNORE-ra. Ugye a default (és az ignorált) signal-handler öröklődik, ezért aztán a tr | head esetén a tr nem kapja meg, szóval ezért köpi ki a végtelen szemetet.

Kezdd a scriptedet azzal, hogy a skywalker után te is újradefiniálod a sigpipe-handlert:

trap - PIPE # use the default SIGPIPE handler

Ettől illenék meggyógyulnia.

=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?

Sajna nem, ezt már tegnap én is próbáltam...


#!/bin/bash
# Add your shell script below

trap - PIPE
trap -p
tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 10 | head -n 1

Output:
trap -- '' SIGPIPE
trap -- '' SIGXFSZ
CI9nirJ5bc
és "Client execution returned "Script killed, timeout of 10 seconds exceeded" (code 1)"
Szóval itt ez a "default".
--
"Sose a gép a hülye."

No jobban utánaolvasva, ez van a bash manualban szó szerint:

" If arg is absent (and there is a single sigspec) or -, each specified signal is reset to its original disposition (the value it had upon entrance to the shell)."

"Signals ignored upon entry to the shell cannot be trapped or reset. ..."

Azaz mivel a szoftvered ignorálja a SIGPIPE-ot, majd (szerintem hibásan) úgy hívja meg a scriptedet, hogy ezt nem állítja vissza default-ba, ezt buktad. Szóval ez szopás, akkor utána kell nézni, hogy ezt a csoda management szoftvert rá lehet-e beszélni, hogy a nyomorult SIGPIPE-ot ne állítsa ignore-ba. Ha nem lehet, akkor marad az, hogy átírod olyanra, hogy ne a végtelenségig olvasson.

=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?

Ansible nem lenne megoldas erre? Script megy akar template-bol es utana mar csak hivni kell. De gyanitom hogy amiket akarsz csinalni arra mar rakatr ansible kesz task/role van...

Esetleg próbáld így:

head -n1 <(fold -w10 <(tr -dc 'a-zA-Z0-9' </dev/urandom))

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

Az első esetben az explicit pipe miatt a shell generál egy alshellt - abban fut a read, ott azért kapod vissza az eredeti értéket. A második esetben nem generálódik alshell, de attól még csinálhat pipe-ot. (Sőt igazából mi mást csinálna, mégse csinálhat ideiglenes fájlt, mert tetszőleges mennyiségű adat elvben betolható ebbe a konstrukcióba, és szerintem nagy gáz lenne, ha teleírná a diszket.)

Szerk: meg is van, man bash:

Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files.

=====
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?

Ha valóban a SIGPIPE a probléma, akkor nem lenne egyszerűbb úgy megoldani, hogy ne legyen szükség rá?
dd if=/dev/urandom bs=1 count=16
Ez pontosan 16 byte-ot fog kiolvasni és annyi.
A tr -dc sem rossz, de nem tudhatod előre, hány karaktert hagy ki - ellenben ha base64 enkódolod a kimenetet, akkor kb. abból a tartományból kapsz eredményt, amit szeretnél. (Mondjuk ehhez már kell openssl vagy valami hasonló a masinára.) Utolsó lépésben a base64-re utaló ==-t levágod a végéről és annyi.