Fórum Root.cz
Hlavní témata => Software => Téma založeno: Ħαℓ₸℮ℵ ␏⫢ ⦚ » 02. 04. 2020, 12:57:07
-
Mám takový problém, pokouším se najít přesné znění příkazu, které jsem zadal do lxterminálu (ale nedostanu se do něj z plochy už! GUI shořelo)
Zadaný příkaz je rsync "petr novak" "pavel jungman" josef cifis - důležité na něm je jen uvozovky a mezery
První pokus
Nicméně vcat /proc/123456/cmdline vidím ,že způsobí:
- mezery nahradí hexaznaky 00
- uvozovky odstraní
- na konec přidá null znak
Takto je to nepoužitelné, když chci příkaz znovu oživit (třeba zkopírovat do schránky v přesném zněí). Například nano editor tam vybleje ^@., textový editor Mousepad ho ani neotevře, skončí na chybové hlášsce o nepodporované znakové sadě, maximálně si ho mohu otrevřít jako UTF-16 a kochat se čínštinou. V tom nákupním seznamu znakových sad aby se prase vyznalo a jsem ani nenašel ASCII tam . Takový editor je zrátka na draka
Chápu že asi jde o nějakou interní reprezenaci příkazu (a asi koherentní). A možná i chápu, že příkaz je interně spuštěn s argumenty ["Petr novak","pavel jungman", "josef","cifis"] a že shell nějak poskytuje konvenci, že mezery jsou separátor argumentů (nejsou-li v uvozovkách)
Druhý pokus byl ps aux | grep pavel - ztratili se uvozovky.
Je nějaká možnost, jak zjistit přesné znění příkazu? Tzn přesně jak jsem ho zadal, aby tam byly správně uvozovky ?
Například:
-nějaká utilita na konverzi proc/cmdline (sed/awk/preg_replace ... jak escapovat null znak?)
-nějaký parametr ps, který neprzní formu příkazu (zachová uvozovky)
- jiný způsob
-
V paměti procesů už původní podoba příkazové řádky není, protože před spuštěním procesu se stane spousta věcí. Zejména do toho zasahuje shell, který provede expanze, nahrazení, interpretaci proměnných a podobně. Navíc jeden odeslaný řádek běžně vyvolává spuštění více procesů nebo subshellů.
Takže jediný, kdo zná podobu zapsaného příkazu na řádku je shell a ten si ho dá do své historie, odkud se dá získat.
-
Ak to nemáte v histórii, je to stratené.
Pred spustením príkazu totiž shell odstráni úvodzovky (quote removal).
Ak napíšete do shellu:
rsync "petr novak" "pavel jungman" josef cifis
Reálne sa spustí rsync so 4 argumentami a samotný rsync už vo svojich argv netuší, že v shelli existovali nejaké úvodzovky či apostrofy obaľujúce viacslovné argumenty.
Je to úplne rovnaké ako:
rsync "petr novak" "pavel jungman" "josef" "cifis"
-
</proc/PID/cmdline xargs -0 printf '%q '
-
Jestli tě zajímá, jak to funguje uvnitř, tak viz Přepisování parametrů příkazové řádky (https://blog.frantovo.cz/c/362/P%C5%99episov%C3%A1n%C3%AD%20parametr%C5%AF%20p%C5%99%C3%ADkazov%C3%A9%20%C5%99%C3%A1dky).
Parametry programu jsou pole textových řetězců, nic jako uvozovky, apostrofy nebo mezery tam nefiguruje – to je jen způsob zápisu toho pole používaný v shellu.
Ty nulové bajty, které jsi našel v souboru cmdline, nenahrazují mezery, ale oddělují prvky toho pole.
Původní zápis můžeš najít v historii shellu nebo bys mohl udělat dump paměti shellu a vyhrabat to odtamtud, ale to asi nechceš. Spíš bych se tedy smířil s tím, že ten původní tvar je ztracený a rekonstruoval bych zápis v shellovském formátu z toho pole – tzn. obalit uvozovkami či apostrofy a escapovat, případně obalovat jen řetězce, kde je to potřeba (obsahující mezery atd.).
-
K prvním 2 odpovědím, to jsem nějak tušil možná o těch ztracených uvozovkách. že mezery uvnitř uvozovek zachová, jsem už zjistil před napsáním dotazu (ale nepodělil jsem se :-[ ) (ale oklikou jsem napsal, že ten tvar je koherentní) (pracovat se souborem historie by byl overkill)
Vlastně tedy mi o uplně přesný tvar nejde (například rsync $source) ale stačí mi argumenty binárky (tedy po escapování a substituci, v příkladu jsem nic takového nepoužil ,takže tento požadavek nebyl dementován)... , ostatně přesně tak jak je vidím v cmdline nebo ps.
a ten trik s xargs "%q " zafungoval (odpověd 1. bod konverze cmdline) ::)
-
K prvním 2 odpovědím, to jsem nějak tušil možná o těch ztracených uvozovkách. že mezery uvnitř uvozovek zachová, jsem už zjistil před napsáním dotazu (ale nepodělil jsem se :-[ ) (ale oklikou jsem napsal, že ten tvar je koherentní) (pracovat se souborem historie by byl overkill)
BTW je práce s historií do shellu zabudovaná, v bashi dáte CTRL+R a napíšete třeba diff, uvidíte poslední použitý příkaz diff. Při opakovaných stisknutích CTRL+R pak vidíte i předchozí výskyty v historii. Případně lze použít něco jako
# grep "diff" ~/.bash_history | tail -n1
-
Ta varianta s xargs -0 a print "%q " je asi to nejpřesnější, co dostanete z běžícího procesu. Escapuje to parametry pro bash, ale samozřejmě to nezná přesnou původní formu ("foo bar" vs. 'foo bar' vs. foo\ bar). Nebudou tam různá přesměrování do/ze souboru (i když, to by se možná taky dalo nějak dohledat).
Například z příkazu:
tail ~/something | grep foo > bar
uvidíte zvlášť tail (s expandovaným ~) a zvlášť grep foo. Přesměrování do souboru bar by možná šlo dohledat jinde, v cmdline to nebude.
-
Přesměrování do souboru bar by možná šlo dohledat jinde, v cmdline to nebude.
V otevřených file descriptorech bude odkaz na obsah toho souboru. Ale jaká byla původní cesta k tomu souboru nezjistíte – on už ten soubor nemusí mít v souborovém systému jméno (může ho držet už jenom ten proces), nebo dokonce pod tím jménem může být v souborovém systému jiný soubor.