Často kladené otázky ku cshellu pod Unix

V nasledovnom texte nájdete vysvetlenia ku mnohým situáciám, ktoré by vás mohli stretnúť pri tvorbe programov v C pod Unix. Nenájdete tu však odpovede na všetko, väčšinou sa tu nespomínajú jednoduché problémy. Ak nenájdete odpoveď v tomto FAQ, použite fórum alebo tútoriály na stránkach predmetu Operačné Systémy.

Zoznam tém aj zoznam otázok sú linky – kliknutím sa presuniete na zodpovedajúce miesto.

Ak sa vam otazky budu zdat cudne, lahke alebo inym z inych pricin nehodne zverejnenia, tak toto su otazky, ktore sa pytali vasi kolegovia na forach rokov minulych ;-).


---------------------------------------- ----------------------------------------

Témy FAQ:




Práca s csh
Práca s adresárovou štruktúrou a súbormi
Program AWK
Úvodzovky
Premenné v cshelli
Otázky k vypracovaniu zadaní
Ostatné otázky


---------------------------------------- ----------------------------------------

Zoznam otázok:
Práca s csh
Standardny chybovy vystup (stderr) v cshelli.
Cyklus foreach.
Vysvetlenie chybovyach hlasok v csh.
If a medzery okolo operatorov.
Exec vo finde a histchars
histchars
Práca s adresárovou štruktúrou a súbormi
Ako zabrániť substitúcii expanzných znakov v rámci mena súboru ?
Ako môžem do findu poslať súbory, ktoré obsahujú medzeru ?
Ako vynechať určitú (známu) časť textového reťazca v mene cesty k súboru ?
Ako sedu oznámiť, že určitú čast textu so znakmi '/' ma považovať za jeden parameter ?
Prečo, keď $dir = pepe, cd $dir a následnom použití foreach file (`ls -a`) nasleduje výpis ACCESS DENIED po príkaze $argv[0] $file ?
Ako vypísať zoznam, do ktorého som si uložil výpis adresára príkazom ls -la tak, ako výpis pri normálnom príkaze ls -la a nie všetko na nový riadok ?
Ako sa dá ošetriť, aby pri porovnávaní prázdnych súborov pomocou cmp nehlásil chybu ?
Ak mám testovací adresár !vykricnik, tak tento program vypíše: vykricnik: Event not found. Ako by sa to dalo ošetriť ?
Ako cez ls -l vypísať obsah adresára tak, že vyseknúť len mená súborov a adresárov ?
Nakoľko treba testovať existenciu súborov, adresárov, userov, či je user prihláseny a podobne ?
Ako spracovat subory s medzerami v nazve?
Doplnenie relativnej cesty na plnu.
Aký tvar má prepínač -exec command v príkaze find ?
Je aj iný spôsob ako zistiť kam ukazuje symbolický link ?
Ako sa dá odstrániť z cesty k súboru (adresáru) iba určitú čast zo začiatku ?
Program AWK
Dajú sa pomocou awk konvertovať malé písmená na veľké ?
Dá sa explicitne prikázať awk, aby bral posledná položku až do konca riadku ?
Ako sa dá do awk dostať premennú ?
Je možné zavolať z awk externý program ?
Ako sa dá vyexportovať z awk premenná (t.j. jej hodnota bez ovplyvnenia výstupu) ?
Je možné uložiť výstup z funkcie system() do premennej v awk ?
Ako sa da odkazat na posledny prvok pola?
Ako jednoducho zmazat posledny znak v riadku?
Ako zistiť najdlhší riadok v súbore ?
Úvodzovky
Ako dostat cely riadok do premennej
Uvodzovky, medzery a premenne...
awk a mkdir
Premenné v cshelli
Set
Zaporny pocet argumentov.
Set na jeden riadok
aby :q fungovalo
Ak máme zoznam, ktorý vyzerá napríklad takto : (" 145 \home\two spaces\a.bat" "147 \home\two spaces\b.bat"). Ako mám z neho vybrať prvú položku (od " po ") aby mi dve medzery po sebe nenahradil jednou a zároveň aby tá nová premenná bola zoznam slov ?
Ako sa dá skontrolovať, či sa do číselnej premennej skutočne uložilo číslo ?
Čo znamená $premenna:q ?
Ako sa zisťuje, či je pole prázdne ?
Aký je rozdiel pri práci s argumentami, medzi zápisom $1 a $argv[1] ?
Ako sa dá zmazať položka zo zoznamu ?
Ako zistím dĺžku stringu v premennej ?
Existuje priamo v c-shell-i spôsob ako zistiť dĺžku reťazca ?
Dajú sa vypísať nejakým príkazom len určité riadky, ak poznáme ich čísla ?
Otázky k vypracovaniu zadaní
Fungovanie testovacich zadani
Je potrebne komentovat pripravne zadania, ktore odovzdavam?
Ostatné otázky
Dá sa skonvertovať IP adresa na hostname a naopak ?
Ako sa dá z premennej, v ktorej je uložený čas vo formáte min:sek získať len údaj o minutách a text do konca reťazca ?
Príkaz last vypíše čas koľko bol človek nalogovaný, ale napr. ak bol nalogovaný z rôznych ttx viackrát, tak to tuším neberie do úvahy a výsledok potom po sčítaní časov je viac ako v skutočnosti bol prihlásený, dá sa to uviesť ako obmedzenie, keď to zadanie odovzdám?
Ako sa dá konvertovať čas medzi rôznymi formátmi ? Konkrétne, ako sa skonvertuje čas ziskaný príkazom ps -o lstart na formát Epoch (počet sekúnd od 1.1. 1970) ?
Ako sa dá ošetriť problém dlhého slova na riadku ? Napríklad niektoré cesty su veľmi dlhé a asi by nebolo múdre ich nejako sekať.
Čo znamená keď LAST vypíše v poslednom poli miesto (HH:MM) niečo takéto : (x+HH:MM), kde x je nejaké číslo,H:M sú samozrejme hodiny:minuty ?
Dá sa vypísať obsah riadku od určitej pozície (od indexu znaku resp. čísla stĺpca) až do konca riadku pomocou zadania nejakého intervalu ?
Ak chceme nájsť procesy používateľov prihlásených zo strojov zadaných ako argumenty, prikaz WHO vypisuje odkiaľ je používateľ prihláseny, ale niekedy ako číselnú IP adresu. Je formát výpisu vždy na ose automaticky pre všetkych ako požadovaný v zadaniach ? (alebo dokáže aj C-shell prevadzat čis. IP na hostname.... asi len funkcia v C-cku alebo treba použiť iný shellovsky prikaz ?).
find | grep
Ako odstranit 'divne znaky' na konci riadku dosovskych txt suborov?
Ako nevytvorit subor, ak by mal byt prazdny?
Ako skonvertovat cas z formatu 'who' na pocet sekund?

---------------------------------------- ----------------------------------------

Práca s csh
Otázka:
Chcel by som sa spýtať na stderr v c-shelli. Čo je to štandardne, výstup na obrazovku (terminál) alebo ide to do nejakého systémom pevne určeného súboru. Ďalej ma zaujíma, či sa dá voľajako presmerovať iba stderr, lebo zatial som videl iba spolocne presmerovanie stdout a stderr ako >&. Potom nevidím význam rozdelenia štand. výstupu na úspešný a chybový.

Odpoveď:
Kazdy beziaci proces v Unix-e ma pristupny standardny vstupny subor, standardny vystupny subor a chybovy vystupny subor. Pristupuje k nim cez deskriptory 0, 1 a 2 (v takomto poradi - t.j. ked proces cita z deskriptoru 0, tak cita obsah standardneho vstupneho suboru). Ake subory to v skutocnosti budu sa urci pred spustenim procesu (jadro OS na to ma systemove volania). Vacsinou to byva tak, ze interaktivne procesy ich maju nastavene na specialny subor - zariadenie - /dev/tty, ktory predstavuje ich terminal. Shell Vam potom poskytuje moznost toto nastavenie zmenit - vykonat presmerovanie vstupu a vystupu - a to pomocou specialnych znakov <, >, atd.
Napr. ked spustite prikaz ls, tak vypisuje na obrazovku (t.j. terminal). Ked spustite ls > out, tak vystup ls bude presmerovany do suboru out.
Co sa tyka presmerovania len chyboveho vystupu v csh, tak to nie je priamo mozne (nepodporuje to csh, ine shell-y to vedia). V csh to nie je asi preto, lebo to nie je bezne potrebne - ved aj ked presmerovavate vystup do suboru, stale by ste chceli byt priamo informovany o vzniknutych chybach.
Ak to ale naozaj chcete a musite urobit, mozete skusit nasledovnu fintu (bez vysvetlenia - to najdete inde):

(ls > stdout) >& stderr


---------------------------------------- ----------------------------------------

Otázka:
Skript:


#! /bin/csh
foreach riadok ("`ps -auxw`")
echo "$riadok"
end

Ked som skript spustil par riadkov prebehlo a vypisalo a potom:
end: No match.
To iste sa dokonca vypisalo aj ked som vymazal echo. Ked som tieto prikazy napisal priamo do prikazoveho riadka prebahli spravne. A fungovali aj v Linuxe. Kde je problem?


Odpoveď:
V csh (nie v tcsh) zoznam hodnot pre prikaz foreach podlieha expanzii znakov *?[] atd. aj ked by nemal. Napr.:


foreach l ("`ps -auxw`")
end

a kedze vystup ps moze obsahovat uvedene znaky, nastane uvedena chyba. Iny pripad:

set a = "taky_nebude*"
foreach l ("$a")
end

Takze ak sa v zozname nachadzaju znaky pouzivane pre expanziu mien suborov, sposobi to uvedenu chybu. Vyhnut sa tomu mozete tak, ze pred takymto cyklom nastavite premennu "set noglob" (cim zrusite expanziu) a po nom ju zrusite "unset noglob". A uplne najlepsie je sa vyhnut cyklu foreach uplne.


---------------------------------------- ----------------------------------------

Otázka:
Nie je v csh nieco, kde by sa dalo najst vysvetlenie chybovych hlaseni? V subore Chybove_hlasky_csh.txt ich je sice dost, ale uz mi to vyhadzovalo kopec chyb, ktorym som prilis nerozumel a pomohlo by aspon tusit v com moze byt chyba.

Odpoveď:
Vacsina chybovych hlaseni v csh je sice velmi strucna, ale na druhej strane je z nich vacsinou jasne, kde je problem (teda ked ich viete prelozit :-).
Prave preto, ze som nenasiel popis chybovych hlasok csh, zacal som vytvarat subor Chybove_hlasky_csh.txt, v ktorom su popisane hlasky, ktore sa vyskytuju najviac, pripadne su problemy s ich vyznamom.
Pokial viete o chybovych hlaskach, ktore by bolo dobre so tohto suboru doplnit, sem s nimi.


---------------------------------------- ----------------------------------------

Otázka:
If a medzery okolo operatorov:
Majme priklad, ze v @ pocet=2
Preco:


if ($pocet >= 2 && $pocet<=4) then ...

vypisuje chybu (if: Expression Syntax) a:

if ($pocet > 1 && $pocet < 5) then ...

to berie v pohode?


Odpoveď:
Problem je asi v tom, ze $pocet<=4 si napisal spolu; ked das medzery okolo relacneho operatora <=, tak by to malo fungovat.
A vysvetlenie je nasledovne (podla man csh):
The shell splits input lines into words at blanks and tabs with the following exceptions. The characters '&' '|' ';' '<' '>' '(' ')' form separate words.
Teda, '>' alebo '<' su samostatne slova a preto ich netreba ohranicovat medzerami. Naproti tomu '>=' uz samostatne slovo nie je a preto je nutne ho oddelit od ostatneho textu medzerami.


---------------------------------------- ----------------------------------------

Otázka:
Exec vo finde
mam taky kod :


find /home/OS/pocitacove/testovaci_adresar/te st3/files -type f -exec /bin/csh -c "cat '{}' | wc -l" \;

ked to spustim, dostanem chybu ze:
!:event not found
skusal som nastavit
set histchars = '' ale ani tak to nefungovalo...

Odpoveď:
Problem je v tom, ze k chybe dojde v csh, ktore je spustene z find-u a preto treba nastavit set histchars = '' v nom. Ked sa totiz objavi vykricnik v mene suboru, tak po nahradeni {} findom sa dostane do skriptu (resp. prikazu) pre csh a ten ho povazuje za znak pre nahradzanie historie.


---------------------------------------- ----------------------------------------

Otázka:
Histchars a exec vo finde:


unset histchars
set histchars = '' ; cat /home/OS/pocitacove/testovaci_adresar/te st3/files/!vykricnik | wc -l

vypise !:event not found
Je to preto, lebo najskor sa nahradi historia a az potom sa nastavi histchars = '' ?
Ale ako potom mozem zabranit prvej substitucii, ked chcem tu postupnost prikazov vykonat v subshelli?

Odpoveď:
Presne tak. Najprv sa nahradza historia a az potom sa analyzuje a vykonava riadok.
Prvej substitucii mozete zabranit iba tak ze to zapisete na dva riadky. Co ale moze byt trosku neprehladne, ked to chcete spustat z find-u.


---------------------------------------- ----------------------------------------

Práca s adresárovou štruktúrou a súbormi
Otázka:

Ako zabrániť substitúcii expanzných znakov v rámci mena súboru ?
Odpoveď:

Toto zabráni nahrádzaniu *, ? atd..
set noglob


---------------------------------------- ----------------------------------------

Otázka:

Ako môžem do príkazu find poslať súbory, ktoré obsahujú medzeru ?
Odpoveď:

Dosiahnete to takto:

set a = "`find '$argv[1]'`"


---------------------------------------- ----------------------------------------

Otázka:

Ako vynechať určitú (známu) časť textového reťazca v mene cesty k súboru ?
Pr.:
echo "ahoj/pokus/pokusik" | sed s/ahoj/cau/

Odpoveď:

Toto síce nahradí ahoj, za cau, ale keďže sed používa na oddelenie parametrov '/' a v súborovej štruktúre Unixu sa rovnaký znak používa tiež, tak sa nedá takýmto spôsobom spravit:
echo "ahoj/pokus/pokusik" | sed s/'ahoj/pokus'/iny_adr/


---------------------------------------- ----------------------------------------

Otázka:

Ako programu sed oznámiť, že určitú čast textu so znakmi '/' ma považovať za jeden parameter ?
Odpoveď:

Riešenie je takéto, keďže namiesto / sa môže použiť ľubovoľný znak (a sed vie ktorý, pretože je prvý za s), napr.
sed 'sXanoXnieX'

alebo je tiež možné / v programe sed escapovat:
sed 's/dir\/file/dir_file/'


---------------------------------------- ----------------------------------------

Otázka:

Prečo po príkaze cd , keď $dir = pepe , cd $dir a následnom použití foreach file (`ls -a`) nasleduje výpis ACCESS DENIED po príkaze $argv[0] $file ? Napr.:
cd $dir #vojdem do adreasára pepe

a následnom použití

foreach file (`ls -a`)
$argv[0] $file

nasleduje výpis ACCESS DENIED hoci adresár v premennej dir má práva 777 ?
Odpoveď:

Problém je v tom, že shell nahrádza aj $argv[0] (pričom by to mala byť chyba, pretože sa indexuje až od 1) a nahradí ho prázdnym reťazcom. Teda výsledkom riadku:
$argv[0] $file

je po nahradení:

pepe

a samozrejme súbor pepe nie je spustitelný a preto shell vyhlási ACCESS DENIED . Keď teda chcete rekurzívne spústať skript, odporúčam Vám používať $0 .
---------------------------------------- ----------------------------------------

Otázka:

Ako vypísať zoznam, do ktorého som si uložil výpis adresára príkazom ls -la tak, ako výpis pri normálnom príkaze ls -la a nie všetko na nový riadok ? Toto nefunguje správne, pretože všetko vypisuje na nový riadok:
set zoznam = "`ls -la`"
foreach item ($zoznam)
echo $item
end

Odpoveď:

Nastavenie zoznamu je OK. Problém je, keď k nemu pristupujete. Totiž po nahradení premennej obsahom sa riadok znova rozseká na slová a tomu musíte zabrániť nasledovne:
set zoznam = "`ls -la`"
foreach item ($zoznam:q)
echo "$item"
end


---------------------------------------- ----------------------------------------

Otázka:

Ako sa dá ošetriť, aby pri porovnávaní prázdnych súborov pomocou programu cmp nehlásil chybu ?
Odpoveď:

Nie je to chyba, len keď porovnávate prázdny a neprázdny súbor, tak cmp zistí, že pri porovnávaní došiel nakoniec jedného z nich a oznámi to. Teda je to forma akou cmp oznámi, že súbory sú nerovnaké. Riešenie - výstup cmp presmerovať na /dev/null a testovať hodnotu $status .


---------------------------------------- ----------------------------------------

Otázka:

Ak mám testovací adresár !vykricnik , tak tento program vypíše: vykricnik: Event not found . Ako by sa to dalo ošetriť ?
if (-rx "$dirs[$i]") then
if ("`ls -A '$dirs[$i]'`" == "") echo "Output: '$dirs[$i]'"
endif

Odpoveď:

Problém je v tom "`ls -A '$dirs'`", pretože premenná $dirs sa nahradí v hlavnom shell-i a druhý shell, ktorý potom spracováva riadok ls -A , už dostane priamo obsah premennej. No a keďže sa potom na riadku nachádza vykričník, chce ho nahrádzať niečim z histórie. Riešenie je jednoduché. Musíte tomu druhému shellu povedať, aby históriu nespracovával (napr. pomocou set histchars = ""). Existuje aj možno lepšie riesenie - vyhnúť sa ls -A ... úplne.


---------------------------------------- ----------------------------------------

Otázka:

Ako cez ls -l vypísať obsah adresára tak, že vyseknúť len mená súborov a adresárov ? Keďže awk nedokáže zobraziť od určitého stĺpca do konca riadku, dá sa použiť prikaz cut -c46 , ale ak je veľkosť súboru príliš veľká, celý výpis sa posunie o jeden znak vpravo, a tak dostanem nesprávny výpis.
Odpoveď:

Jedna možnosť je zobrať posledné pole na riadku, ale to nefunguje, keď je v mene súboru medzera alebo je to symbolická linka. Druhá možnosť (o niečo zložitejšia) je nájsť, kde sa vo vypise ls -l nachádza dátum a viete, že hneď za ním až do konca riadku je meno súboru. Tretia (a možno najvhodnešia) možnosť je použiť na výpis niečo iné ako ls - napríklad príkaz find vie cez klauzulu -printf vypísať len to, čo naozaj potrebujete (napr. veľkost súboru a jeho meno) v takom tvare v akom potrebujete pre ďaľšie spracovanie.


---------------------------------------- ----------------------------------------

Otázka:

Nakoľko treba testovať existenciu súborov, adresárov, userov, či je user prihláseny a podobne ?
Odpoveď:

Malo by sa určite testovať či adresáre (súbory, ...) zadané ako parametre spĺňajú požiadavky (teda či sú to naozaj adresáre, či sú pristupné, ...) no a potom ďalej pri ich prechádzaní by ste mali zabezpeciť, aby skript nespadol napr. na neprístupnom adresári. Pri používateľoch treba testovať, či zadaný používateľ naozaj v systéme existuje (/etc/passwd ).


---------------------------------------- ----------------------------------------

Otázka:
Ako spracovat subory s medzerami v nazve?
Mam problemy so subormi (adresarmi), v kt. je medzera. Tu je cast kodu, kt. mi v zadanych adresaroch najde subory, kt. bude treba kopirovat a v cielovom adresari vytvori stromovu strukturu adresarov, v kt. sa dane subory vyskytuju.
Zistil som, ze problem je az v samotnom awk. A to v tej zatvorke po slove system. Ked to dam len vypisat cez prikaz print, tak je to vsetko tak ako ma byt (teda nazvy su aj s medzerami), ale ako nahle to dam do system(), tak sa vytvoria len adresare s nazvom po prvu medzeru.

foreach adresar ($pociatocne_adresare:q)
cd $adresar
find . -type f -name "[a-zA-Z]*" -exec dirname {} \; | sed '/\.\//s///' | grep -v '^\.' |\
uniq | awk -v ciel=$cielovy_adresar '{system ("mkdir -p "ciel"/"$0)}
end


Skusal som rozne kvotovanie, uvodzovkovanie a apostrofovanie ale nic nepomohlo.

Odpoveď:
Jednoducha rada. NEPOUZIVAJTE system() v awk !
a) su s tym problemy
b) system pouziva na spustanie zadanych prikazov shell sh (t.j. nie csh) ==> iny shell, ina syntax, ine problemy
c) skripty mate robit v csh a nie v sh

Takto to vsak funguje:


... | awk '{system ("mkdir -p \"'"$cielovy_adresar/ "'"$0"\" ")}'

Alebo aj takto:

#!/bin/csh
set adresar = "budu aj medzery"
echo skuska | awk -v adr=$adresar:q\
'{p=sprintf("mkdir %c%s%c",34,adr,34);system(p)} 9;

(uvodzovky maju ASCII kod 34).

A este aj takto:

set adresar = "budu aj medzery"
echo skuska | awk '{system("mkdir \"'$adresar:q'\&quo t;")}'


takze: uvodzovky su backslahovane, aby zostali v stringu, ktory sa odovzda funkcii system(). Nebackslashovane uvodzovky su tam preto, lebo do funkcie system sa odovzdava retazec a inak je to klasicka obchadzka cez ukoncenie AWK programu - premennu rozvinie shell - a znova program zacneme. AWK vykona:

system("mkdir "budu aj medzery"")

Aj ked je to napisane 'zle', ale je tomu rozumiet, ze ?
Samozrejme, takto to zapisat nemozno, pretoze uvodzovky, ktore musia byt v prikaze mkdir "budu aj medzery" sa biju s uvodzovkami, ktore sluzia v AWK na zapis retazca - preto to backslashovanie.


---------------------------------------- ----------------------------------------

Otázka:
Ako efektivne doplnit relativnu cestu na plnu, teda od korenoveho adresara? Pri prehladavani programom find som skusal pouzit prepinac -print, ale to nemalo pozadovany efekt. Pri obycajnom spojeni cety, ku pracovnemu adresari, s relativnou cestou (napr.: `pwd`/../../dev ), je sice vysledok korektny, ale neviem, ci sa hodi na vystup. Nie je nejaky prikaz, kotry by automaticky doplnal relativnu cestu na uplnu?

Odpoveď:
Na doplnenie relativnej cesty na absolutnu pouzi nieco taketo:


set absCesta = "`cd $relCesta; pwd `"
No samozrejme predtym musis zistit ci v $relCesta je skutocne nejaka cesta, lebo inac ti cd vypise chybu, takze napr:

if(! -d "$relCesta")
echo "Error: Zla cesta" > dev/stderr
endif
POZOR - Pojem plna cesta, pouzivany v zadaniach nie je totozny s pojmom absolutna cesta. To, ze mate vypisat plnu cestu k najdenemu suboru znamena, ze nestaci vypisat len meno suboru ale aj cestu, ktora k nemu vedie (zacinajuc tym, co bolo zadane).
napr.

najdi.csh tento/adresar
vypise

Output: 'tento/adresar/iny/adresar/subor& #039;
alebo

najdi.csh ../iny
vypise

Output: '../iny/subor'
alebo

najdi.csh /tmp
vypise

Output: '/tmp/adresar/subor'


---------------------------------------- ----------------------------------------

Otázka:

Aký tvar má prepínač -exec command v príkaze find ?
Odpoveď:

Ten prepínač má tvar -exec prikaz {} \; Pričom tie zátvorky sa nahradia menom každého nájdeného súboru. Ten príkaz sa vykoná nad každým nájdeným súborom. Dôležité sú lomítko a bodkočiarka na konci.
find /home -exec cat {} \;

Vypíše každý nájdený súbor na stdout .
---------------------------------------- ----------------------------------------

Otázka:

Je aj iný spôsob ako zistiť kam ukazuje symbolický link ? Napr.:
`filetest -L meno_linku`

Odpoveď:

Tento postup funguje len v tcsh a je ekvivalentný zápisu:
if (-L meno_linky) ...

Csh nepozná test na symbolickú linku a treba to urobiť ináč. Napríklad podľa výstupu príkazu ls :
if ("`ls -l meno_linky`" =~ l*) ...


---------------------------------------- ----------------------------------------

Otázka:

Ako sa dá odstrániť z cesty k súboru (adresáru) iba určitú čast zo začiatku ? Napr. keď mám zoznam s položkami (/home/os/csh/doc home/os/csh/pocitacove /home/os/csh) a chcem odstrániť z každej home/os.
Odpoveď:

Môžete to urobiť napríklad použitím programu sed :
echo "$polozka" | sed 's+/home/os++'

čo by malo byť to, že na každom riadku (v tomto prípade iba na jednom - tom, ktorý mu pošle echo ) odstráni reťazec /home/os (resp. nahradí ho (s ako substitute) prázdnym reťazcom). Alebo keď viete, že to má určitý počet znakov:
echo "$polozka" | cut -c 9-


---------------------------------------- ----------------------------------------

Program AWK
Otázka:

Dajú sa pomocou awk konvertovať malé písmená na veľké ?
Odpoveď:

Áno, ale jednoduchšie by to bolo pomocou tr:
echo "$text" | tr a-z A-Z

Pomocou awk napríklad vyriešime problém, ak reťazec začína veľkým písmenom skonvertuje všetky znaky na veľké a podobne sa to dá aj naopak:
echo $xx | awk '{if($0 ~ /^[[:upper:]]/) print(toupper($0))}'


---------------------------------------- ----------------------------------------

Otázka:

Dá sa explicitne prikázať awk, aby bral posledná položku až do konca riadku ?
Odpoveď:

Naneštastie to nejde. Skúste sa ale pozrieť na funkciu substr(s,i[,n]) a pomocou nej získať to, čo potrebujete.
---------------------------------------- ----------------------------------------

Otázka:

Ako sa dá do awk dostať premennú ?
Odpoveď:

Je niekoľko spôsobov, tu sú tri z nich:
awk -v p=111 'BEGIN {print p}'
set p = 111; echo $p | awk {print $0}
set p = 111; awk 'BEGIN {print '"$p"'}'


---------------------------------------- ----------------------------------------

Otázka:

Je možné zavolať z awk externý program ?
Odpoveď:

Ale samozrejme, veď awk je veľmi inteligentný program - dá sa to napríklad takto:
awk '{system ("ls -la")}'


---------------------------------------- ----------------------------------------

Otázka:

Ako sa dá vyexportovať z awk premenná (t.j. jej hodnota bez ovplyvnenia výstupu) ?
Odpoveď:

Nedá - awk predsa číta súbory (resp.štandardný vstup) a zapisuje na štandardný vystup (resp. do súborov). Tak ako nie je možné k premenným shellu pristupovať z iných programov (sú len v jeho adresnom priestore), tak to nie je možné ani k premenným awk . Snáď jediná možnost ako dosiahnut to čo chcete, je poslať obsah premennej (vo vhodnom formáte) na výstup a z neho ho potom prevziať, prípadne ich zapísať do dočasného súboru.
---------------------------------------- ----------------------------------------

Otázka:

Je možné uložiť výstup z funkcie system() do premennej v awk ?
Odpoveď:

Je možné zistiť len exit status, awk totiž neposkytuje mechanizmus `prikaz` tak ako csh. Funkcia system() je v awk určená na spúšťanie externých príkazov podľa spracovaného vstupu - teda napr. poslať mail pre každý riadok vstupu, spustiť program rm a pod.
---------------------------------------- ----------------------------------------

Otázka:
Ako sa v AWKacku da odkazat na posledny prvok pola?
napriklad:


#rozdeli retazec foo do pola bar podla ":", tj. napr:
#foo="aaa:bbb:ccc" => bar[1]="aaa", bar[2]="bbb" a bar[3]="ccc"
split(foo,bar,/:/)

a potrebujem zistit, kolko prvkov ma pole bar.

Odpoveď:
Ked pouzivas split na vyrobenie pola, tak je to jednoduche - samotny split vracia pocet poloziek pola (navratova hodnota).
Ked ale ziskas pole nejakym inym sposobom, tak to vo vseobecnosti asi nejde.
Polia v awk su asociativne a indexom moze byt v podstate cokolvek. Takze v principe nepotrebujete poznat pocet prvkov v poli - totiz ked potrebujete prejst vsetky prvky, aj tak musite pouzit for+in, pretoze neviete, ake indexy su pouzite. No a pre tych par pripadov, ked to potrebujete si jednoduche pri kazdom pridani do pola zvysite pocitadlo.


---------------------------------------- ----------------------------------------

Otázka:
Ako jednoducho zmazat posledny znak v riadku?

Odpoveď:
Pomocou sed: sed 's/.$//'
teda nahradite (substitute - s) regularny vyraz .$ (teda jeden znak na konci riadku) prazdnym retazcom.
Alebo pomocou awk:
awk '{print substr($0, 1, length()-1)}'


---------------------------------------- ----------------------------------------

Otázka:

Ako zistiť najdlhší riadok v súbore ?
Odpoveď:

Length v awk je funkcia, ktorá má jeden parameter (resp. ked ho nezadáte, zistuje dĺžku $0 ). Malo by to byť:
awk '{print length(), $0}' subor | sort -n


---------------------------------------- ----------------------------------------

Úvodzovky

---------------------------------------- ----------------------------------------

Otázka:
Uvodzovkovanie
Potrebujem spravit,aby v set links = `ls -l | awk '{print $0}'` som dostal za kazdu polozku links CELY riadok prikazu. Nijak mi to neslo (na Linuxe).

Odpoveď:
V awk print bez parametrov vypise $0, takze print $0 je zbytocne.
Je potrebne to nasledovne zaqotovat:
set links = "`ls -l | awk '{print "'$0'"}'` "
pretoze musis vonkajsiemu shellu zrusit specialny vyznam znaku $ pri zapise $0 - '$0' vonkajsi shell nenahradi, ale az awk.


---------------------------------------- ----------------------------------------

Otázka:


%set skuska="viac medzier"
%echo "$skuska"
vypis:viac medzier
%set prem=`echo $skuska`
%echo "$prem"
vypis:viac medzier

problem z tohto je zjavny, pri prvom vypise je este v premennej $skuska spravny pocet medzier, ale v druhom vypise je uz v premennej $prem iba 1 medzera, toto sposobuje problem pri praci s menami adresarov a suborov, ake je riesenie?

nefunguju ani nasledujuce:

%set prem=`echo "$skuska"`
%set prem="`echo $skuska`"
%set prem=`echo '"'$skuska'&quo t;'`
%set prem=`echo "'$skuska'"`


Odpoveď:
Vzhladom na to, ze vnutorny shell (subshell), ktory spracovava prikaz medzi ``, znova analyzuje zadany riadok, treba aj jemu premennu zaquotovat (Samotne `` nequotuju).
Takze po jednom:
>%set prem=`echo "$skuska"`
Toto len zaquotuje premennu vo vnutornom shelli. Nesmiete zabudnut na to, ze vystup prikazu v `` sa este rozsekava na slova.

>%set prem="`echo $skuska`"
Tu ste uz zabezpecili ze sa vystup rozseka po riadkoch (a teda jednoriadkovy vystup echo zosttne pokope), ale nazaquotovali ste premennu.

>%set prem=`echo '"'$skuska'&quo t;'`
Vnutorny shell vidi zaquotovane uvodzovky a nezaquotovanu premennu ...

>%set prem=`echo "'$skuska'"`
Tu vnutorny shell vidi apostrofy zaquotovane v uvodzovkach a vonkajsi shell to rozseka po slovach.

Spravne riesenie je:


set prem = "`echo '$skuska'`"
alebo

set prem = "`echo "\""$skuska"\ ""`"
alebo

set prem = "`echo "\$"skuska:q`"
Zaujimavejsie je toto:

set prem = "`echo "\$"skuska:q`"
pretoze az vnutorny shell "uvidi" $skuska:q, zaquotuje to po prvkoch a nahradi.


---------------------------------------- ----------------------------------------

Otázka:
Vyvstal jeden problem s vytvorenim adresara s medzerami v nazve pomocou awk (nezlaknite sa, to je len na ilustraciu parsovania :)
prikaz pre cshell:


awk 'END {a="a b";system("mkdir '\''"a"& #039;\''")}' /dev/null

ako to pracuje?


Odpoveď:
cshell sparuje apostrofy ', ktorych obsah bude brat za retazce (backslash apostrof \' samozrejme nie je zaciatok retazca) a vytvori argument prikazu awk:



END {a="a b";system("mkdir '"a"'")}

awk vytvori retazce podobne ibaze z uvodzoviek ", apostrofy tu budu iba obycajne znaky (to a za mkdir je interna premenna awk, ktora sa nahradi jej obsahom) a prikaz system dostane argument v tvare:
mkdir 'a b'
ktory sa teda vykona spravne.


---------------------------------------- ----------------------------------------

Premenné v cshelli

---------------------------------------- ----------------------------------------

Otázka:
Ked dam

set prem
set prem2 = ( )
tak:
echo $#prem .......... 1
echo $#prem2 .........