Ubuntu Suomen keskustelualueet
Ubuntun käyttö => Ohjelmointi, palvelimet ja muu edistyneempi käyttö => Aiheen aloitti: Dost - 19.11.21 - klo:22.29
-
Tervehdys! Miten luoda yksi muuttuja joka tarkoittaisi mitä tahansa numeroa vaikkapa 1-5 tai vain joitakin esim. 2,3,5?
Eli pitäisi saada siistimmin ja helpommin tehtyä tätä samaa:
#!/bin/bash
lause=$(cat tiedosto.txt)
if [[ $lause == "tässä on numero 1" ]] || [[ $lause == "tässä on numero 2" ]] || [[ $lause == "tässä on numero 3" ]] || [[ $lause == "tässä on numero 4" ]] || [[ $lause == "tässä on numero 5" ]]
then
echo "yahoo!"
fi
exit
Tavoite on saada se näyttämään noin tälläiseltä:
#!/bin/bash
num="1 || 2 || 3 || 4 || 5"
lause=$(cat tiedosto.txt)
if [[ $lause == "tässä on numero $num" ]]
then
echo "yahoo!"
fi
exit
Mutta miten tehdään tuo "num"-muuttuja oikealla tavalla?
-
En kyllä äkkiseltään keksi ”nättiä” ratkaisua Bashille, koska ilmeisesti ( | ) -notaatio ei toimi if-lauseissa.
Zsh:ssa onnistuu kahdellakin tavalla, joko numeroita etsien tai vaihtoehtoja etsien:
#!/bin/zsh
setopt extended_glob
while read lause; do
# etsi numero väliltä 1–5
[[ $lause == "tässä on numero "<1-5> ]] && print jahuu
# etsi vaihtoehto 1, 3 tai 5
[[ $lause == "tässä on numero "(1|3|5) ]] && print jahuu
done
Muoks: Sen verran lisäisin, että
lause=$(cat tiedosto.txt)
on Bashissakin paremmin:
lause=$(<tiedosto.txt)
Mutta minun käyttämäni while read -silmukka on sikäli parempi, että silloin luettavan tiedoston voi antaa uudelleenohjauksena komentoriviltä ja sitä luetaan rivi kerrallaan.
-
Yön yli mietittyäni totesin, että case-lauseellahan tuo onnistuu, tosin hieman säätäen.
#!/bin/bash
while read lause; do
# tämä vain jotta näkee alkuperäisen rivin
echo $lause
lause=${lause##*numero }
case $lause in
(1|3|5) echo jahuu
;;
(2|4|6) echo jihuu
;;
esac
done
”lause=${lause##*numero }” poistaa yksinkertaisesti riviltä kaiken ennen numeroa, koska vaihtoehdot pitää antaa kokonaisina (= eivät voi sisältää *-osia).
-
Yön yli mietittyäni totesin, että case-lauseellahan tuo onnistuu, tosin hieman säätäen.
#!/bin/bash
while read lause; do
# tämä vain jotta näkee alkuperäisen rivin
echo $lause
lause=${lause##*numero }
case $lause in
(1|3|5) echo jahuu
;;
(2|4|6) echo jihuu
;;
esac
done
”lause=${lause##*numero }” poistaa yksinkertaisesti riviltä kaiken ennen numeroa, koska vaihtoehdot pitää antaa kokonaisina (= eivät voi sisältää *-osia).
Jep, kiitos! Korvaan siis if:in case:lla. Just sopivasti mun tarkoitukseen nuo ";;" -väkäset näyttävät korvaavan elif:inkin.
Zsh on mulle uusi konsepti, enkä taida ymmärtää voiko sen ja bash:in sekoittaa samassa skriptissä.
-
Viitaten SuperOscarin vastaukseen tuosta bash-shellin taulukoista, niin on totta, että [] -notaatio ei toimi, mutta mitenkäs --threads -parametri, äkkiseltään katsoin tuosta varmistukseksi hakukoneelta, niin tässä suora linkki artikkeliin, jossa käsitellään juuri alkuperäisen kysyjän esittämään ongelmaan ratkaisua perusteissa:
https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays (https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays)
Samassa artikkelissa on esimerkki, miten viitataan johonkin tiettyyn alkioon, on tuossa näköjään taulukon iterointikin, ja sitten alkioiden lisääminen taulukkoon (array populating)
Lisään vielä UNIX-historiasta, että noissa ensimmäisen sukupolven shelleissä ei ollut muuttujia, esimerkiksi ensimmäisessä Thompson Shellissä, joka on Ken Thompsonin käsialaa, ja muistaakseni sitä käytettiin vähän yli 1970-luvun puoliväliin asti.
Noista toisen sukupolven shelleistä varmaan Bourne on ensimmäisiä, joissa oli jonkinlainen alkeellinen taulukointi, tai viittausjärjestelmä taulukon kaltainen, mutta bash on käsittääkseni paljon myöhemmin julkaistu, niin kyllä varmaan kaikissa nykyisissä Linux-koneissa käytössä olevat shellit omaavat taulukkorakenteen.
-
Viitaten SuperOscarin vastaukseen tuosta bash-shellin taulukoista, niin on totta, että [] -notaatio ei toimi, mutta mitenkäs --threads -parametri, äkkiseltään katsoin tuosta varmistukseksi hakukoneelta, niin tässä suora linkki artikkeliin, jossa käsitellään juuri alkuperäisen kysyjän esittämään ongelmaan ratkaisua perusteissa:
Eikö tässä ollut kysymys enemmän vaihtoehtojen antamisesta mahdollisimman kätevästi kuin varsinaisesti taulukoista? Eli tuo alkuperäinen ongelmarivi:
if [[ $lause == "tässä on numero 1" ]] || [[ $lause == "tässä on numero 2" ]] || [[ $lause == "tässä on numero 3" ]] || [[ $lause == "tässä on numero 4" ]] || [[ $lause == "tässä on numero 5" ]]
…on ongelmallinen vain koska on pakko toistaa koko ”lause”? Taulukko tai vastaava on sinänsä yksi mahdollinen ratkaisutapa, mutta kun Bashissa ei ole (?) myöskään operaattoria jäsenyyden tarkistamiseksi, sekään ei käy.
Pythonissa voi tehdä vaikka näin:
if lause in [f'tässä on numero {n}' for n in range(1, 6)]:
Nätti ei ole tuokaan mutta välttää sentään koko lauseen tuskallisen uudelleenkirjoittamisen!
Muoks: Ja nyt kun asiaa vielä ajattelen, toimiihan Bashissa sentään (( … )) -syntaksi kuten Zsh:ssakin, joten tämäkin kävisi:
lause=${lause##*numero }
(( lause >= 1 && lause <= 5 )) && echo numero väliltä 1–5
Tosin sillä edellytyksellä, että rivin lopussa varmasti on kelvollinen kokonaisluku!