Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Karlitos 14. 03. 2015, 17:44:35

Název: Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: Karlitos 14. 03. 2015, 17:44:35
Zdravím,

snažím se teď proniknout do kódování v bashi a mám trocho problém s chápáním některých věcí které bude asi nejlepší vysvětilit na příkladech.

Při poznávání jak funguje cut  jsem si zkoušel upravit výstup příkazu ps. Narazil jsem na problém, že cut -d " " bude dělit řádky po  mezerách, ale to nefungovalo jak mělo pro libovonlý počet mezer. Hledal jsem jak pro parametr -d zadat libovolný počet mezer, ale cut očekává jeden character.

Nakonec jsem našel řešení přez tr -s " ", což v řetězci nahradí libovolné množství mezer za jednu jedinou a tak příkaz
Kód: [Vybrat]
ps -aux | tr -s ' ' vyhodí seznam procesů kde jsou v řádcích sloupečky oddělené jen jednou mezerou.

Pak jsem se to snažil dát do skriptu a narazil na tyhle věci:
Kód: [Vybrat]
PROC=`ps -aux`
echo $PROC
vypíše výstup z ps bez zalamování do jednoho řádku. Aby se mi výtup zalomil musím použít
Kód: [Vybrat]
PROC=`ps -aux`
echo "${PROC}"
Což funguje ale zatím jsem nepřišel na to proč tomu tak ja/musí být.

No ale jak teď udělat to odstranění vícečetných mezer ?
Kód: [Vybrat]
echo $(echo $PROC | tr -s ' ') mi všechno vypíše do jednoho řádku.

Ve výsledku bych se moc rád dobral stejného výstupu jako když v terminálu zadám
Kód: [Vybrat]
ps -aux | tr -s ' ' | cut -d " " -f1,2,3,4 Vím že na ostranění vícečetných mezer lze použít awk/sed ale já bych hlavně moc rád pochopil jak to s tím víceřádkovým výpisem je a kde dělám co blbě.

Diky!
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: # 14. 03. 2015, 18:36:08
moc nechapu proc si to komplikujes tou dalsi zavorkou

Kód: [Vybrat]
PROC=`ps -aux`
echo "${PROC}" | tr -s ' ' | cut -d " " -f1,2,3,4
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: libcha 14. 03. 2015, 18:45:09
Nepochopil jsem úplně co je cílem, ale pokusím se pomoct.

Proč prostě neduěláš:
PROC=`ps -aux | tr -s ' ' | cut -d " " -f1,2,3,4`
echo "$PROC"

nebo ještě lépe:
PROC=`ps -axo user,pid,%cpu,%mem | tr -s ' '`
echo "$PROC"

(ale to by bylo pro učení se moc jednoduché ;) )

Vysvětlení některých zmíněných jevů:

PROMENNA=`prikaz_jehoz_vystup_obsahuje_newliny_a_mezery`
...do proměnné se uloží výstup tak jak je

echo "$PROMENNA"
...vypíše obsah proměnné tak jak je

echo "${PROMENNA}"
...to samé, je to užitečné jen ve chvíli kdy chceme třeba vypsat "${PROMENNA}neco navic" nebo používat substituce

echo $PROMENNA
...$PROMENNA se rozvine do více parametrů příkazu echo. Je to jako kdybys napsal třeba
echo ahoj cau \
nazdar tepic
tak příkaz echo vidí že má 4 parametry a vypíše je za sebe oddělené mezerami. čímž nastane to, že se vždy za sebou jdoucí sada libovolných bílých znaků (vč newline) přemění na jednu mezeru

echo `prikaz` $(prikaz) "$(prikaz)"
rozdíl mezi `...` $(...) je velice malý (za úkol si ho zjisti), já raději používám to druhé kvůli čitelnosti. (Ne)uzavření výrazu do uvozovek má stejný následek jako u proměnné.


...už je alespoň něco jasné ? :)
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: Karlitos 14. 03. 2015, 19:00:03
Díky! Cílem je pochopit jak funguje skriptování v bashi a prohloubit znalosti. Já sem začínal na Javě a docela dobře dávám Python, ale u bashe stále dost bojuju se syntaxí a podobně.

Vidím že chyba byla v těch uvozovkách a moc děkuju za vysvětlení. Po třetím přečtení mi to konečne docvaklo celé :-D
Budu s tím teď zase trochu dál hrát a uvidíme kam se dostanu.
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: nobody 14. 03. 2015, 19:08:05
libcha: dobre skolitel ;) a to stacilo napsat, protoze zavrene do "" to zustane jako jeden parameter :) tak aspon dodam:
- informace o tom ze echo parametry oddeluje automaticky mezerou je v: help echo (help prikaz - jde o napovedu internich prikazu bash), nebo man echo pri pouziti samostatneho echo prikazu
- pokud script ma v hlavicce #!/bin/bash pouzije se interni echo bashe, to funguje jak je receno
- pokud script a v hlavicce #!/bin/sh pouzije se samostatnej echo prikaz(sh interni nema), ten vyzaduje pro stejne chovani parametr -e (protoze narozdil od interniho echo prikazu bashe to nema jako defaultni chovani(aby newline representoval jako novyradek))
- i pri pouziti bash lze vynutit ve scriptu pouziti samostatneho echo napr:
ECHO=$(which echo)
$ECHO "text"
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: karel 14. 03. 2015, 19:14:33
Hledej "Vilém Vychodil: Příručka českého uživatele".
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: Karlitos 15. 03. 2015, 10:23:13
Děkuju ještě jednou všem za vysvětlení. Narazil jsem ale na jednu nejasnost:

Očekával jsem ,že následující příkaz bude správný podle vzoru "$(prikaz)":
Kód: [Vybrat]
echo "$($PROC | tr -s ' ')"Jenže to tr -s ' ' se neprovede.

Když odstraním závorky tak to funguje:
Kód: [Vybrat]
echo $PROC | tr -s ' 's tím ale, že echo interpretuje to co je napravo zase jako vícečetný vstup.

Když celý příkaz zavřu mezi uvozovky tak dostanu víceřádkový výstup, ale bez odstranění vícečetných mezer
Kód: [Vybrat]
echo "$PROC | tr -s ' '"
No a správně funguje
Kód: [Vybrat]
echo "$PROC" | tr -s ' '
Mě to mate. Očekával bych že se tento příkaz bude interpretovat jako: interpretuj hodnotu proměnné PROC, udělej z ní řetězec a pošli to na vstup tr, kde se odstraní vícečetné mezery a toto bude vstupem echo, které to bude považovat za vícečetný vstup

Proto jsem čekal že by měla fungovat verze  "$(prikaz)" což se ovčem neděje.
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: libcha 15. 03. 2015, 10:55:30
V prvním příkazu voláš něco uložené v $PROC a předáváš to pajpou do tr. Zřejmě jsi zapomněl jedno echo:
Kód: [Vybrat]
echo "$(echo $PROC | tr -s ' ')"(pozor na to že $proc uvitř tu stále není v uvozovkách...

V druhém příkazu asi chápeš co se děje - je to obsah uvnitř $(...) v mnou opraveném prvním příkazu.

Třetím příkaz vypíše to samé co
Kód: [Vybrat]
echo "$PROC" jen se na konci výstupu objeví | tr -s ' '
Je to proto, že se echuje to co je uzavřené v uvozovkách - zde tedy i symboj pajpy, jméno příkazu tr a jeho "parametry".

Čtvrtý příkaz už asi zas chápeš.
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: Karlitos 15. 03. 2015, 13:26:39
Aha díky moc  :)

Odpovědi vedou bohužel k dalším otázkám. Ale mám pocit, že už začínám nacházet i vlastní odpovědi.

Mátlo mě  proč bylo potřeba dát to chybějící druhé echo do příkazu
Kód: [Vybrat]
echo "$(echo $PROC | tr -s ' ')"když to přeci fungovalo i stylem
Kód: [Vybrat]
echo "$PROC" | tr -s ' '
Pak mě ale došlo že jsem ten druhý příkaz nejspíš interpretoval chybně, tedy:
Udělej výstup do terminálu (echo) z: hodnoty proměnné PROC poslané skrz pipe na tr -s '  ' Tedy jako kdyby tam byla za echo závorka určijící pořadí vykonávání echo ($PROC | tr -s ' ')

Jenže takto asi pipe perátor nefunguje, předpokládám že nemůže dostat hodnotu promněnné pomocí $PROMENNA ale musí dostat výstup nějakého příkazu tedy echo $PROMENNA

Správná interpretace toho druhého příkazu by tedy asi měla být:
Udělej výstup do terminálu (echo) z hodnoty proměnné PROC a celý výstup pošli  skrz pipe na tr -s '  ' který předpokládám dělá standartně výstup do stdout a proto se to vypíše. A proto když to celé ještě uzavřu do $( ... ) tak si to můžu uložit do další promněnné.

Asi to říkám blbě ale začíná se mi to pomalu jasnit. Tedy doufám  ;)
Název: Re:Bash, víceřádkový výstup a odstranění mezer
Přispěvatel: nobody 15. 03. 2015, 14:33:11
...
předpokládám že nemůže dostat hodnotu promněnné pomocí $PROMENNA ale musí dostat výstup nějakého příkazu tedy echo $PROMENNA
...

promenou tim ziskas ale pouzije se jako prikaz, viz to me nastaveni externiho prikazu echo do promene ECHO (http://forum.root.cz/index.php?topic=10868.msg124594#msg124594)...
pokud ji chces zobrazit, spravne uz ti doslo ze prikazem na zobrazeni :)

dalsi tema k zamysleni je ze s promenou se daji delat veci o kterejch se ti jeste nestni ;)
napr. kdyz budes chtit zmenit obsah nejake promene, muzes to udelat takto:
echo "Nova hodnota je: $(echo $stara | sed 's/neco/zaneco/g')"
jenomze, pokud se podivas sem (http://tldp.org/LDP/abs/html/parameter-substitution.html) nebo sem (http://wiki.bash-hackers.org/syntax/pe) zjistis ze totozne docilis timto:
echo "Nova hodnota je: ${stara//neco/zaneco}"
:)