Kirjoittaja Aihe: Ohjeita shell-skriptaukseen (bash)  (Luettu 376551 kertaa)

nm

  • Käyttäjä
  • Viestejä: 16426
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #80 : 06.08.11 - klo:18.48 »
Goto+label toimii varmaan BASHissa vieläkin koska grep löytää niitä binäärisistä skripteistä joista ei saa ohjelmalistausta että näkisi varmasti

Bashissa ei ole goto-komentoa, eikä mahdollisuutta esikääntää skriptejä. Ne "binääriset skriptit" ovat siis todennäköisesti jollain muulla kielellä kirjoitettuja ja käännettyjä ohjelmia. Jotkut shell-skriptit voivat myös sisältää pätkiä muilla kielillä kirjoitettua ohjelmakoodia. Ainakin perl-skripteissä näkyy usein goto-käskyjä.

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #81 : 08.08.11 - klo:17.02 »
BASH:issa ei tosiaan ole goto-komentoa - sillä BASH:issa koko sana goto jätetään pois vaikka toiminta säilyykin - itseasiassa koska myös palataan niin kyseessä on "gosub x of ..." tyyppinen sirpalekäsikranaatti.

Ei siis voi pompata rivinumeroon eikä label:iin vaan ainoastaan funktioon. Funktioon mennään kun sen nimi mainitaan joko selväkielisenä nimenä tai muuttujan arvona. Varsinkin kun mennään muuttujan arvon mukaiseen paikkaan on syytä kirjoittaa esimerkiksi näytölle tai tiedostoon mitä tehdään:

- sinne mihin pompataan: echo "tänne: ${FUNCNAME[0]} tultiin paikasta:" ${FUNCNAME[1]}     
- sinne mistä lähdetään: echo "${FUNCNAME[0]} riviltä: $LINENO  hypätään funktioon:"$funktion_nimi
- echo "skriptin nimi on: ${@: -0}"
- echo kutsupino: ${FUNCNAME
  • } > tiedostonimi

- kutsupinon merkitys: funktiolla tulee olla tieto mihin palata - tämä pino on kylläkin käyttäjän kannalta vain nähtäväksi. Kun johonkin funktioon mennään laitetaan paluuosoite pinoon ja palattua se poistetaan. Koska funktiot voivat kutsua toisiaan niin pinosta voi tulla huomattava - myös rekursiossa jokaisella kutsulla pino kasvaa.

- jos ei tuommoisia lisää niin vuosien kuluttua on tekijälle itsellekin täysi mysteeri kuinka johonkin on jouduttu.
- jos toteutus on sellainen että näyttö menisi sekaisin täytyy tulostaa tiedostoon. Silloin vain lisätään perään: > tiedostonimi.

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

Parametritkin palautuvat automaattisesti - ellei hölmöile niinkuin usein neuvotaan. Käytännössä tuota parametrien siirtymistä kuvaava skripti voi olla seuraavantyyppinen:

Koodia: [Valitse]
#!/bin/bash
function lue () {
 echo -n "kirjoita teksti "$1":"
 read -e $1  # kirjoitettavaa voi editoida ja ääkkösetkin toimii
             # sanoissa saa olla useampiakin epämääräisen pituisia välilyönti-jaksoja
             # myös päätteen historiasta saa tekstiä nuolinäppäimillä.
}

lue a        # huomaa että parametri on muuttujan nimi eikä arvo.
echo "a sai arvon:$a"
lue b
echo "a on vieläkin:$a    ja b sai arvon:$b"


Koska funktiot ovat BASH:in "goto-käskyn" oleellinen osa on niitä syytä kuvata:

Funktio voidaan muodostaa kahdella tavalla:
1. funktion_nimi () { normaali BASH-skripti ; } # jolloin funktio jakaa muistialueen pääohjelman kanssa. Muodostuva funktio avautuu samaan prosessiin kutsujansa kanssa joten se on nopea - kutsu kestää noin 15 mikrosekuntia. Tätä tapaa käytetään lähes aina.
2. funktion_nimi () ( normaali BASH-skripti ; ) # siis sulut ovat muuttuneet kaarisuluiksi. Tällöin funktio muodostetaan omaan prosessiinsa joten sillä on muunmuassa ihan oma muistiavaruus. Sen kutsu kestää noin 350 mikrosekuntia, ja parametrien palauttaminen vaikeutuu. Mutta toiminnallisesti se on melkein samanlainen.
 
BASH:in funktioiden ominaisuuksista:
1. Funktio voi kutsua itseään ihan samallatavalla kuin muutkin. Rekursio on siis helppo toteuttaa. Ja rekursiosta voidaan palata joko lopetusehdon täytyttyä tai määräkertojen jälkeen tai...
2. jos mitään muuta ei määrätä palataan funktiosta kun se on kokonaan suoritettu ja palataan siihen lauseeseen mikä on heti kutsunjälkeen. Funktiossa voi kylläkin olla return-käsky kesken koodin mutta sekin palaa kusun jälkeiseen lauseeseen. Mutta on leegio menetelmiä joilla voi palata ihan jonnekin muualle - esimerkiksi toiseen funktioon ja kutsupinoa käsittelemällä paluu sieltä tapahtuu pääohjelmaan - tai esimerkiksi ctrl-c:llä funktioon joka selvitää miksi äsken hyydyttiin tai sekoiltiin.

- funktiolla voi olla melkeinpä millainen nimi hyvänsä, esimerkiksi ! tai ^ kelpaa hyvin tai mikä hyvänsä lause jossa ei ole välilyöntiä - välilyönnin voi korvata merkillä _ .

- pääohjelmassa voi kutsua vain funktioita jotka on määritelty jo. Mutta funktioissa voi kutsua sellaista joka määritellään vasta myöhemmin. Liitetyistä kirjastoista voidaan aina kutsua.
- normaalisti funktioiden ja pääohjeman muuttujat ovat yhteisiä joten parametrien palauttamiseen ei ole aina syytäkään. Mikäli funktiokutsussa on annettu sen muuttujan nimi jota halutaan muuttaa niin koska funktiossa voidaan määrätä esimerkiksi: read $1 ei parametria edes tarvitse palauttaa.
- pahat pojat väittävät ettei funktio kykene palauttamaan parametreja. Sillä on kuitenkin merkitystä vain silloin kun käytetään funktiokutsua joka toimii omassa prosessissaan - siis tuo aikaisemmin kuvattu tapa 2 jota ei juuri koskaan käytetä. Mutta keinoja palauttaa sittenkin parametreja on monia:
1. funktio voi kirjoittaa levylle ja pääohjelma lukee sen sieltä. Ja RAM-levyllä homma on nopeaakin.
2. Kuvaannollisesti käsky: a=$(joku_funktio jolla voi olla parametrejakin) lukee näytöltä mitä joku_funktio on tulostanut. Keino toimii olipa funktio globaalialueella tai omassa funktiossaan. Voidaan soveltaa useammallekin muuttujalle.
3. funktiolle annetaan parametriksi muuttujan nimi ja sitten koodissa jossakin määrätään esimerkiksi: read $1  - silloin syötetyn muuttujan arvo muuttuu. Ei siinä mitään eval-käskyä tarvita. Vaikka tämä menetelmä toimii vain globaalialueen funktioissa niin sillä on merkitystä koska silloin funktiota voidaan kutsua käsittelemään erinimisiä muuttujia niin että syötetyn muuttujan arvo muuttuu. Näin voidaan käsitellä vaikka kuinkamontaa muuttujaa.

Koodia: [Valitse]
- funktioille voi syöttää kahdentyyppisiä parametreja:
  1. Arvo (by value). Tällöin vastaanottavassa päässä parametreihin viitataan: $1, $2 ....$N. Tai entisvanhaan: ${@:N} jolloin N:llä ei ole rajaa. Lopustapäin laskettuna toiseksiviimeinen: ${@:(-2):1}
  2. Nimi. (by reference). Tällöin vastaanottavassa päässä parametriin viitataan:  =${!N}    
- seuraavilla parametreilla on erikoismerkitys:
$* parametrien joukko $0 mukaanlukien ( $0 on funktion nimi )
$@ parametrien joukko, sama kun kirjoittaisi "$1" "$2" "$3" .... Parametri $0 siis jää pois
$# parametrien lukumäärä, parametria $0 ei lasketa mukaan. Siis: [ $# -lt 1]" -> mikäli parametreja ei ole
$$ ytimen tunnus
$! viimeksi suoritetun prosessin tausta-prosessin tunnus
$? viimeksi suoritetun  käskyn paluuarvo
$- oletusarvo?
$_ heti kutsun jälkeen suoritettavan skriptin täydellinen tiedostonimi ( siis polkuineen). Muulloin viimeiseksi suoritetun käskyn viimeinen argumentti.   

Ohjelmille voidaan antaa myös optioita, miinus-merkin edeltämiä kirjainsarjoja tyyliin: ls -lpr

parametrien joukko          ${@}   
\$1 --------------------->  $1       
\$2 --------------------->  $2       
skriptin prosessinimi       ${0}     # joka on BASH_SOURCE pääohjelmassa   
skriptiä polku ja nimi      ${0%/*} 
oma nimeni                   ${0##*/}



« Viimeksi muokattu: 20.04.19 - klo:16.30 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #82 : 14.08.11 - klo:04.43 »
Linuxin (ja myös Ubuntun) käsky ls ei tulosta tiedostonimiä oikein jos niissä on välilyönti. Teinpähän korvaavan funktion joka huomioi oikein myös sellaiset tiedostonimet joissa on välilyönti - tosin se on vielä ihan kapula-asteella mutta pääasiahan on että se toimii ja on riittävän nopea - ja ideanhan siitä saa revittyä mihin skriptiin tahansa.

Koodia: [Valitse]
#!/bin/bash
function tiedostolistaus () {
kansio=$@ # kun listattavaksi tulee kansio jonka nimessä on välilyönti siirtyy jokainen sana omassa parametrissaan ja ne täytyy liittää yhteen
echo '( ' > delme
find "$kansio" -maxdepth 1 -name "*" -type d | sort | while read Rivi  
do
  [[ $Rivi = $kansio ]] && echo '".edellinen kansio."' >> delme || echo -n \'${Rivi##*/}\'' ' >> delme
done
find "$kansio" -maxdepth 1 -name "*" -type f | sort | while read Rivi  
do
  echo -n \'${Rivi##*/}\'' ' >> delme
done
echo ' )' >> delme
eval Valittavat=$(cat delme )
rm delme
}

read -p 'minkä kansion listauksen haluat: ' kansio
tiedostolistaus "$kansio"  
echo -e ' '"${Valittavat[@]/%/\n}"
read -p 'paina enter jatkaakseesi'

- tiedostonimissä olevat välilyönnit ovat ongelmallisia kaikissa tehtävissä, mutta suurin osa selviää noudattamalla muutenkin järkevää periaatetta että tekstijonot täytyy laittaa heittomerkkien väliin. Esimerkiksi välilyönnin sisältävät tiedoston kotihakemistoosi saat käskyllä: touch /home/$(whoami)/"katin kontit" ja poistettua käskyllä: rm /home/$(whoami)/"katin kontit"

- myös kansioiden nimissä sallitaan välilyönnit

 Mutta esimerkiksi editoitaessa täytyy joissakin tapauksissa käytää semmoistakin rakennetta kuin: eval gedit "tiedostonimi".

- tarkoituksena on kiertää ongelmia joita esitetään sivulla: http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29 tavalla joka ei vaadi minkäänlaisia muutoksia tiedostonimeen. Vika on käskyn ls toteutuksessa; tiedostojärjestelmä sinällään sallii melkein mitävain; esimerkiksi kansion jonka nimi on: * tai joka sisältää mitä merkkejä vaan (paitsi kova lainausmerkki: ' )

muoks: lisätty yksinkertainen ajuri
« Viimeksi muokattu: 16.09.11 - klo:02.55 kirjoittanut petteriIII »

nm

  • Käyttäjä
  • Viestejä: 16426
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #83 : 15.08.11 - klo:16.19 »
Linuxin (ja myös Ubuntun) käsky ls ei tulosta tiedostonimiä oikein jos niissä on välilyönti.

ls -b

ajaaskel

  • Palvelimen ylläpitäjä
  • Käyttäjä
  • Viestejä: 3401
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #84 : 16.08.11 - klo:10.50 »
Lainaus
Vaan itseasiassa kyse oli siitä että tuollaiset nimet täytyy laittaa lainausmerkkien väliin...

Lisäksi käytetään "pehmeää" ja "kovaa" lainausta:

"Tämä on pehmeä lainaus"
'Tämä on kova lainaus'

Sangen usein joudutaan käyttämään lainauksia "suojaamaan" eli osoittamaan että nuo sanat joiden välissä on välilyöntejä tarkoittaakin yhtä asiaa.  Tiedostonimien kanssa törmää tuohon usein.

Kannattaa myös kokeilla tulostaa lainausmerkki echo: n avulla  :)
« Viimeksi muokattu: 16.08.11 - klo:10.56 kirjoittanut ajaaskel »
Autamme ilolla ja ilmaiseksi omalla ajallamme.  Ethän vaadi, uhoa tai isottele näin saamasi palvelun johdosta.

retu

  • Käyttäjä
  • Viestejä: 949
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #85 : 16.08.11 - klo:11.49 »
Vaan itseasiassa kyse oli siitä että tuollaiset nimet täytyy laittaa lainausmerkkien väliin että niitä voisi käsitellä. Esimerkki: luo tiedosto: touch "nimi jossa on välilyönti". Käske: ls -> tulostuu ihan oikein. Käsky: gedit nimi jossa on välilyönti  
ei onnistu. Sensijaan onnistuu kun käskee:  gedit "nimi jossa on välilyönti"
Tai sitten:
Koodia: [Valitse]
touch nimi\ jossa\ on\ välilyönti
gedit nimi\ jossa\ on\ välilyönti

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #86 : 17.08.11 - klo:16.44 »
Kätevää. En heti huomannutkaan. Oletan että olette vanhoja ohjelmoijia niinkuin minäkin ja minun ja niin varmaan teidänkin mielestänne tuommoinen on oikeastaan ihan hyväksyttävää sillä ketä tuo haittaa jos lauseessa on muutama keno ylimääräistä? Mutta nuoret käyttäjät eivät hyväksy mitään mikä viittaakaan meidän vanhuksien meininkeihin ja BASHin tulevaisuus riippuu heistä. Todella kätevä silti tuo: ls -b .

Kun tiedostonimi alkaa miinuksella niin <ls -b> tulostusta täytyy vähän mukaella: gedit -- -alkuinen\ nimi.
Mutta entäpä jos alussa onkin --  ? En löytänyt konstia mutta eiköhän semmoinen jostain löydy. (optioiden eteen tulee joskus -- )
Mutta entäpä jos alussa onkin $-merkki ? Eteen keno: gedit \$alkuinen\ nimi . Näitähän riittää, ja usein ne vaativat pieniä muutoksia. Mutta tuo esittämäni selviää sinällään lähes kaikista. Mutta niinkuin sanoin se on vielä kapula-asteella. Esimerkiksi vasta kun Ajaaskel puhui kovasta ja pehmeästä lainauksesta tajusin muuttaa lainat  koviksi.

Tai kansio jonka nimessä on merkki * . Silloin ei käsky ls toimi.

Editoitaessa skriptiä tai sen dokumenttia olisi kiva jos editoriin avautuisi eri lehdille myös muutamia aikaisempia editointeja koska silloin on helppo kokeilla mikä toimii sillä vanhaan on helppo palata. Tämä tuo esiin nuo käskyt: eval gedit .... Ja silloin ei kenoja tai muita virityksiä hyväksytä; siis mitään ylimääräistä ei hyväksytä mutta erikoismerkit ja ääkköset kyllä hyväksytään.
« Viimeksi muokattu: 10.09.11 - klo:06.35 kirjoittanut petteriIII »

nm

  • Käyttäjä
  • Viestejä: 16426
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #87 : 17.08.11 - klo:19.59 »
Kun tiedostonimi alkaa miinuksella niin <ls -b> tulostusta täytyy vähän mukaella: gedit -- -alkuinen\ nimi.
Mutta entäpä jos alussa onkin --  ? En löytänyt konstia mutta eiköhän semmoinen jostain löydy. (optioiden eteen tulee joskus -- )

Hoituu samalla tavalla: gedit -- --abc

Jos haluat saada ls:llä aikaan listauksen, josta voi suoraan poimia mitä tahansa tiedostonimiä komentoriville, se onnistuu parhaiten parametrilla --quoting-style=shell tai --quoting-style=shell-always. (- ja -- -alkuiset nimet ovat tosin tällöinkin hankalia.)
« Viimeksi muokattu: 17.08.11 - klo:20.08 kirjoittanut nm »

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #88 : 18.08.11 - klo:07.17 »
Ihan tosissani kysyn sillä en ole saanut virallista koulutusta Linuxiin: luuloja on ja netistähän löytää vaikka mitä ja kirjojakin on mutta eivät ne kunnon koulutusta vastaa.

Käsittääkseeni tiedostonimeen ei normaalisti kannata laittaa erikoismerkkejä niinkuin esimerkiksi merkkiä " . Kuitenkin skriptini salli sen niinkuin ainakin merkit - ja $; nautiluskin näyttää ne ihan kiltisti, ja niitä voi käsitellä normaalisti. Kieltämättä vaikeuksia tulee kokoajan vastaan vaan tuntuvatpa selviävän.

- merkkiä ' se ei käsittele oikein ja taitaa jäädä ikuisesti toimimattomaksi. Merkki / on vielä pahempi.
- niin muuten myös erikoismerkkejä sisältävät tiedostonimet näkyvät skriptiajurissa semmoisenaan, esimerkiksi: "vaikea tiedostonimi" (lainausmerkkien kanssa) tai $dollari poikineen  ja käyttö tapahtuu samoin kuin tavallistenkin nimien.
- nyt olen kokeillut ääkkösillä runsaasti, mutta vain paikallisella levyllä. Toimii teoriassa aivan kivasti. Mutta vaikeuksiakin on: esimerkiksi käsky basename toimii joskus kummallisesti varsinkin kun sekä kansionnimessä että tiedostonnimessä on erikoismerkkejä.

Hölmöyshän tässä vaivaa: minunpuoleltani koko juttu alkoi siitä, että kun nautiluksella tekee tiedostosta backupin samaan kansioon tiedoston nimeltä: <tiedostonimi> (kopio), siis sekä välilyönti että sulkumerkki. Osittain homma on siis virallisesti hyväksytty.
« Viimeksi muokattu: 24.08.11 - klo:04.40 kirjoittanut petteriIII »

retu

  • Käyttäjä
  • Viestejä: 949
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #89 : 18.08.11 - klo:09.40 »
Dashin l. tavuviivan käsittelyn optiona l. vipuna voi kiertää myös lisäämällä nimeen polun.
Koodia: [Valitse]
gedit ./--abc
Dollariin puree myös yksinkertainen (kova) hipsu, mutta keno on monesti kätevämpi. Cygwin käyttäjille vinkki:
Koodia: [Valitse]
rm -r \$Nt*windows hakemistossa tekee kivasti lisää  levytilaa.

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #90 : 18.08.11 - klo:20.15 »
Aikoinaanhan kovasti varoiteltiin ettei pidä käyttää ääkkösiä skriptien nimissä ja jopa tehtiin skriptejä jotka muuttaa ne tavallisiksi aakkosiksi kaikkialla koneessa.

Jo parivuotta olen käyttänyt skriptien nimissä ääkkösiä eikä koskaan ole tullut mitään harmia. Funktioiden nimissä käytin myös ääkkösiä pari-vuotta sitten ja toimi kivasti, mutta jotenkin tuntui siltä että on viisainta hylätä ääkköset funktionimissä.
Mutta mikähän on noiden ääkkösten tilanne Ubuntussa virallisesti ottaen ?

Käsittääkseeni paikallisten levyjen kanssa ei tule ongelmia muiden kuin / kanssa? Mutta vekkokovalevyt ja muut joita käytetään oman käyttöjärjestelmänsä kautta ovat epävarmoja, ja vain UTF-8:a käyttävät toimivat ongelmitta?
« Viimeksi muokattu: 22.08.11 - klo:04.46 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #91 : 22.08.11 - klo:14.38 »
Skripti on teoriassa lyhyt sillä skriptintekemisen vaikeudet kasvavat skriptin pituuden myötä exponentiaalisesti.

Jos kuitenkin tekee pitkän skriptin niin tekemisen vaikeuksista yksi pahimpia on se että järjestelmään on usein lisätty käskyjä paketeilla ja kun Ubuntun kehittäjät päättävät ettei jotain pakettia enää laitetakaan peruskokoonpanoon lakkaavat jotkut skriptit toimimasta ja ilmoittavat: "käskyä ei löydy" mutta kukaan ei kerro mikä käsky sen on aiheuttanut ja millä rivillä se on.

Nämä ilmoittava funktio on tekeillä, mutta on vasta ihan alkutekijöissään eikä funktio vielä etsi sitä onko käsky kenties jossain tunnetussa paketissa mutta sen pitäisi olla pieni ongelma ja eiköhän se kohtapuoleen tule.

Lisäät vain skriptiisi yhden funktion eikä mitään muuta edes voi tehdä, ei mitään viittauksia siihen eikä mitään muutakaan:      

function command_not_found_handle () {
  echo "ohjelma:"${BASH_SOURCE}" Rivino:"${BASH_LINENO}
  echo "seuraavaa käskyä ei löydy: \""$1\"""
  echo "käskyn argumentit ovat: \""$2\"" \""$3\"""   # $4, $5 ...
  read -p '- jokakerran kun komentoa ei löydy niin pysähdytään ja jatketaan kun painetaan enter'
}

- kyseessä on bash4:n ominaisuus = toimii vain uudehkoilla Ubuntuilla.
« Viimeksi muokattu: 24.08.11 - klo:12.13 kirjoittanut petteriIII »

ajaaskel

  • Palvelimen ylläpitäjä
  • Käyttäjä
  • Viestejä: 3401
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #92 : 22.08.11 - klo:15.47 »
Lainaus
"command not found" eikä missään kerrota mikä käsky sen on aiheuttanut

Käytännössä tuo kai menee niin päin että jotkut "ulkoiset" komennot ovat vakiona kaikissa jakeluissa ja sellaiset jotka liittyvät esim. desktop -ympäristöön (Gnome, KDE, ...) joutuu skriptissä itse testaamaan ensin eli joko mikä desktop tai sitten itse komentoa löytyykö se koneesta ennen kuin käyttää sitä asioiden tekemiseen ohjelmassa.
Itse koen hankalimmaksi skriptien kirjoituksessa pikkutarkan syntaksin "tyhjän tilan" suhteen, esimerkiksi jossain pitää olla välilyönti ja jossain toisessa paikassa sitä ei saa missään tapauksessa olla.
Hauskinta bash: in kanssa on että lyhyelläkin koodin pätkällä voi saada ihmeen paljon aikaan. Netistä löytyy usein käyttökelpoisia ideoita jonkin asian toteuttamiseen.  Niitä kannattaa hieman keräillä aina kun osuu silmään jokin kätevä tapa tai idea.
Autamme ilolla ja ilmaiseksi omalla ajallamme.  Ethän vaadi, uhoa tai isottele näin saamasi palvelun johdosta.

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #93 : 22.08.11 - klo:16.13 »
Itse koen hankalimmaksi skriptien kirjoituksessa pikkutarkan syntaksin "tyhjän tilan" suhteen, esimerkiksi jossain pitää olla välilyönti ja jossain toisessa paikassa sitä ei saa missään tapauksessa olla.

Puhut asiaa; ainakaan minun päässäni ei säännöt pysy ja jokakerta menee kokeiluksi.

retu

  • Käyttäjä
  • Viestejä: 949
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #94 : 23.08.11 - klo:15.09 »
Lainaus
"command not found" eikä missään kerrota mikä käsky sen on aiheuttanut
Riippuu mistä roikkuu eli noinhan siinä käy, jos komennat jotain odottamatonta
Koodia: [Valitse]
$ ärkele
ärkele: command not found
mutta viisaampia neuvoja tulee, jos ohjelma on pakettivarastossa, vaikkei asennettu
Koodia: [Valitse]
$ ncftp
The program 'ncftp' is currently not installed.  You can install it by typing:
sudo apt-get install ncftp
tai jos jotain samankaltaista olisi tarjolla
Koodia: [Valitse]
$  zedit
No command 'zedit' found, did you mean:
 Command 'gedit' from package 'gedit' (main)
 Command 'dzedit' from package 'dzedit' (universe)
 Command 'xedit' from package 'x11-apps' (main)
 Command 'edit' from package 'mime-support' (main)
 Command 'nedit' from package 'nedit' (universe)
 Command 'iedit' from package 'xnc' (universe)
 Command 'jedit' from package 'jedit' (universe)
 Command 'medit' from package 'medit' (universe)
 Command 'ledit' from package 'ledit' (main)
zedit: command not found

nm

  • Käyttäjä
  • Viestejä: 16426
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #95 : 23.08.11 - klo:18.16 »
mutta viisaampia neuvoja tulee, jos ohjelma on pakettivarastossa, vaikkei asennettu
Koodia: [Valitse]
$ ncftp
The program 'ncftp' is currently not installed.  You can install it by typing:
sudo apt-get install ncftp

Tuollaisia neuvoja saa kuitenkin vain vuorovaikutteisessa päätteessä, eli skriptiä pitäisi ajaa bashin -i -vivulla. Tällä puolestaan on useita muita sivuvaikutuksia. Kuten ajaaskel jo totesi, skripteissä normaali käytäntö on tarkistaa kaikkien niiden kutsuttavien ohjelmien olemassaolo, joiden ei voida olettaa kuuluvan kohdejakelun peruskokoonpanoon.

Paketoiduissa skripteissä tilannetta helpottaa paketin pakollisten riippuvuuksien määrittely, mutta silloinkin skriptissä on syytä olla samat tarkistukset ja selkeät virheilmoitukset.

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #96 : 29.08.11 - klo:02.55 »
Vipu -i ei tuntunut toimivan kun käskyn nimi on aivan eri kuin paketin nimi kuten lähes poikkeuksetta *tools paketeissa määriteltyjen käskyjen kanssa on.
Saattaa hyvinkin olla että kyseiset käskyt kuuluvat luokkaan 'obsolete, vanhentunut' tai että vain kokeilin väärin. Kiinnostaisihan tuo tietää, mutta tähän asiaan se ei vaikuta: kyseinen paketti pitäisi saada automaattisesti ladattua. Ainakin omaan koodiin sen saa helposti.

Koska grep-aptavail on määritelty paketissa dctrl-tools tekee skripti rekursion jonka jälkeen se vasta tietää ladata oikean paketin. Tottakai rekursio on paha juttu ja siitä kannattanee pyrkiä eroon. Mutta tulipa kokeiltua ja toimii tällähetkellä niinkuin toimii 'normaaleillakin' käskyillä.

Tässä koodi uudistettuna ja mukana tälläkertaa pieni yhdenrivin pääohjelma mukana testaustarkoituksessa. Pääohjelman tilalla voi olla mikätahansa skripti jolloin jokaisella ajokerralla ladataan yhden tuntemattoman käskyn paketti niin kauan että kaikki käskyt on määritelty. Hidasta ja huonoa vielä, mutta kun toiminta on puoli-automaattista niin tietää virheitä korjatessaan tarkemmin missä mennään.

- mikäli käskyn edessä on sudo toiminta taitaa siirtyä root:in command_not_found_handleen; kai sen joskus kerkiää kokeilla.

Koodia: [Valitse]
#!/bin/bash

function command_not_found_handle () {
  komennon_nimi=$1
  shift
  echo "ohjelma:"${BASH_SOURCE}" Rivino:"${BASH_LINENO}
  echo "seuraavaa käskyä ei löydy: \""$komennon_nimi\"""
  echo "käskyn argumentit ovat: ""$@"
  echo
  kaskysta_on_puhuttu_paketeissa=$(apt-cache search $komennon_nimi)
  [[ $(echo $kaskysta_on_puhuttu_paketeissa | grep ^$1) ]] && paketin_nimi=$(echo $kaskysta_on_puhuttu_paketeissa | grep ^$1) ||
paketin_nimi= $(echo $kaskysta_on_puhuttu_paketeissa | awk {'print $1'}) # onko tämä or-osa tarpeen ?
  echo " paketin määrittelyä: "$paketin_nimi #; read
  sudo apt-get install ${komennon_nimi} || echo "siitä on puhuttu paketeissa: "$kaskysta_on_puhuttu_paketeissa
  exit
}

grep-aptavail bar # halutaan tutkia tarkemmin niitä paketteja joissa komennosta bar puhutaan. Ladataan käskyn grep-aptavail määrittelevä paketti mikäli sitä ei jo ole.
# atop
« Viimeksi muokattu: 29.08.11 - klo:11.37 kirjoittanut petteriIII »

jekku

  • Käyttäjä
  • Viestejä: 2624
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #97 : 08.10.11 - klo:05.25 »
...
Googlella löytää kyllä ideoita. Ja 'yhdenrivin skriptejä' - joista useat jopa toimii.
...

Törmäsin kiusalliseen kuvioon ylen liveradion kanssa.
Ajoittain otan talteen jotain komennolla:
mplayer -dumpstream -cache 1024  -dumpfile $outfile &
ja kutsuvassa skiptissä on sleep joka ampuu homman alas annetun ajan jälkeen.

Mutta, liian usein eka yritys epäonnistuu ja outfileen tallentuu vain:
[Reference]
Ref1=http://mediak.yle.fi/liveradiosuomi?MSWMExt=.asf
Ref2=http://10.1.6.5:80/liveradiosuomi?MSWMExt=.asf

Ja komento 'file' paljastaa myös, että kyse ASCII -tekstistä eikä  M$:n ASF:sta

Saako tuon kutsun loopattua jotenkin, siis niin kauan kun outfile on tekstiä niin yrittää uudelleen ja uudelleen. (Toki annetun rajan verran yrityksiä)


ajaaskel

  • Palvelimen ylläpitäjä
  • Käyttäjä
  • Viestejä: 3401
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #98 : 08.10.11 - klo:13.28 »
Ehkä näin: Katso heksaeditorilla mitä siellä on tiedoston alussa kun kaikki toimii ok.  Jos uuden tiedoston alku ei sisällä tuota niin edetään sen mukaisesti.  Siellä saattaa lukea "ID3" jos teet mp-kolmosia.  Tai saahan sen tuon "file": n avulla myös --- vai oliko itse looppaaminen se ongelma ?
Testi ensin tiedoston sisällölle ja "while" looppi joka yrittää uusiksi ja testaa tiedoston statuksen sitten ?  Vai oliko tuossa jokin muu juttu ?   Auttaisiko muuten "fuser" niin että ei tarvitse odottaa jotain kiinteätä aikaa ?
« Viimeksi muokattu: 08.10.11 - klo:13.55 kirjoittanut ajaaskel »
Autamme ilolla ja ilmaiseksi omalla ajallamme.  Ethän vaadi, uhoa tai isottele näin saamasi palvelun johdosta.

jekku

  • Käyttäjä
  • Viestejä: 2624
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #99 : 08.10.11 - klo:17.45 »
Ehkä näin: Katso heksaeditorilla mitä siellä on tiedoston alussa kun kaikki toimii ok.  Jos uuden tiedoston alku ei sisällä tuota niin edetään sen mukaisesti.  Siellä saattaa lukea "ID3" jos teet mp-kolmosia.  Tai saahan sen tuon "file": n avulla myös --- vai oliko itse looppaaminen se ongelma ?
Testi ensin tiedoston sisällölle ja "while" looppi joka yrittää uusiksi ja testaa tiedoston statuksen sitten ?  Vai oliko tuossa jokin muu juttu ?   Auttaisiko muuten "fuser" niin että ei tarvitse odottaa jotain kiinteätä aikaa ?

Joo, siis looppaaminen on hukassa, "file" kyllä paljastaa sen sisällön.
(Pitääpä yrittää kurkata mitä mplayer palauttaa silloin kun heittää pyyhkeen kehään kun ei löydä streamia - josko mitään.)