Ubuntu Suomen keskustelualueet

Ubuntun käyttö => Ohjelmointi, palvelimet ja muu edistyneempi käyttö => Aiheen aloitti: Dost - 19.11.21 - klo:22.29

Otsikko: BASH - Muuttuja joka tarkoittaisi vain joitakin numeroita?
Kirjoitti: 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:
Koodia: [Valitse]
#!/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ä:

Koodia: [Valitse]
#!/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?
Otsikko: Vs: BASH - Muuttuja joka tarkoittaisi vain joitakin numeroita?
Kirjoitti: SuperOscar - 19.11.21 - klo:22.52
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:

Koodia: [Valitse]
#!/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ä

Koodia: [Valitse]
lause=$(cat tiedosto.txt)
on Bashissakin paremmin:

Koodia: [Valitse]
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.
Otsikko: Vs: BASH - Muuttuja joka tarkoittaisi vain joitakin numeroita?
Kirjoitti: SuperOscar - 20.11.21 - klo:10.18
Yön yli mietittyäni totesin, että case-lauseellahan tuo onnistuu, tosin hieman säätäen.

Koodia: [Valitse]
#!/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).
Otsikko: Vs: BASH - Muuttuja joka tarkoittaisi vain joitakin numeroita?
Kirjoitti: Dost - 20.11.21 - klo:14.06
Yön yli mietittyäni totesin, että case-lauseellahan tuo onnistuu, tosin hieman säätäen.

Koodia: [Valitse]
#!/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ä.
Otsikko: Vs: BASH - Muuttuja joka tarkoittaisi vain joitakin numeroita?
Kirjoitti: Jere Sumell - 20.11.21 - klo:22.57
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.
Otsikko: Vs: BASH - Muuttuja joka tarkoittaisi vain joitakin numeroita?
Kirjoitti: SuperOscar - 21.11.21 - klo:17.02
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:

Koodia: [Valitse]
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:

Koodia: [Valitse]
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:

Koodia: [Valitse]
lause=${lause##*numero }
(( lause >= 1 && lause <= 5 )) && echo numero väliltä 1–5

Tosin sillä edellytyksellä, että rivin lopussa varmasti on kelvollinen kokonaisluku!