Kirjoittaja Aihe: Pieni bash scripti kysymys [ratkaistu]  (Luettu 2483 kertaa)

tjka

  • Käyttäjä
  • Viestejä: 144
    • Profiili
Pieni bash scripti kysymys [ratkaistu]
« : 31.01.15 - klo:13.19 »
Moi !

Ohjelmointitaidot on niin rajalliset  :-[  että välillä on pakko vähän kysellä apuja...
Eli, kuinka saan scriptissä suurimman numeron tiedostosta muuttujaksi?

Tiedoston sisältö on seuraavanlainen:

abc:1001
def:1002
ghij:1033
klmn:2001
op:2022
qrstu:3333


-tjka-
« Viimeksi muokattu: 01.02.15 - klo:13.12 kirjoittanut tjka »

AimoE

  • Käyttäjä
  • Viestejä: 2782
    • Profiili
Vs: Pieni bash scripti kysymys
« Vastaus #1 : 31.01.15 - klo:14.09 »
Tällainen kysymys panee aina tarkistamana ensin onko kysyjä aikaisemmin kysellyt koulutehtäviltä vaikuttavia asioita. Nyt kun tarkistus on tehty, ja koska kysyjä aina korostaa ettei tee ohjelmointia, tyydyn antamaan minimaalisen vastauksen ilman selityksiä (olettaen että tiedoston nimi on 'tiedosto'):

Koodia: [Valitse]
sort -t: -k2 -g tiedosto | tail -n1 | sed 's/.*://'
Tosin tuossakin on -g ihan vaan siltä varalta että tiedoston kaikki numerot eivät ole nelinumeroisia tai ylipäätään samanmittaisia. Jos tiedosto on yhtään erilainen kuin annetussa esimerkissä, ratkaisu on heti erilainen.

nm

  • Käyttäjä
  • Viestejä: 16430
    • Profiili
Vs: Pieni bash scripti kysymys
« Vastaus #2 : 31.01.15 - klo:14.37 »
Itse taas avaan mielelläni vastaukset, jolloin kysyjällä ja muilla aiheeseen eksyvillä on mahdollisuus oppia jotain. Tässä hieman erilainen ratkaisu.


Jos kaikki numerot ovat samassa "sarakkeessa", kuten esimerkkisyötteessä, jossa kaksoispiste on sarakkeiden erottaja, operaatio onnistuu komennoilla cut, sort ja tail, jotka kuuluvat Unixin perustyökaluihin:

Koodia: [Valitse]
cut -d : -f 2 tiedosto.txt | sort -n | tail -n 1
Tässä cut-komennolla leikataan syötteestä toinen sarake. Parametri -d : asettaa sarakkeiden erottajaksi (delimiter) kaksoispisteen ja -f 2 valitsee toisen sarakkeen/kentän.

Seuraavaksi sarake putkitetaan sort-komennolle, joka järjestää alkiot pienimmästä suurimpaan. Parametri -n valitsee kokonaislukujen numeerisen sorttauksen, joka järjestää esimerkiksi arvot 99 ja 100 oikeaan numeeriseen järjestykseen toisin kuin merkkijonosorttaus. AimoE:n ehdottama parametri -g toimii myös; se osaa sortata kokonaislukujen lisäksi liukuluvutkin.

Lopuksi tail-komennolla leikataan järjestetystä listasta viimeinen eli suurin arvo ja tulostetaan se. Tuloksen voi sijoittaa muuttujan arvoksi tähän tapaan:

Koodia: [Valitse]
suurin=$(cut -d : -f 2 tiedosto.txt | sort -n | tail -n 1)

Yllä esitetty on koodin puolesta helppo tapa hoitaa homma, mutta sorttaus on suhteellisen raskas operaatio maksimin tai minimin etsimiseen. Sen sijaan riittää käydä lista kerran läpi ja verrata jokaisessa kohdassa listan arvoa aiemmin löydettyyn maksimiarvoon. Alussa maksimiksi asetetaan nolla (tai negatiivisten lukujen tapauksessa pienin mahdollinen arvo). Koodia:

Koodia: [Valitse]
file="tiedosto.txt"

column=$(cut -d : -f 2 "$file")
max=0

for val in $column; do
    if [ "$val" -gt "$max" ]; then
        max="$val";
    fi
done

echo "$max"

Lisäksi ohjelmaan voi joutua tekemään tarkistuksen tilanteelle, jossa listassa ei ole ainuttakaan lukua. Silloin ei välttämättä haluta palauttaa arvoa 0 vaan tehdään jotain muuta.
« Viimeksi muokattu: 31.01.15 - klo:14.40 kirjoittanut nm »

AimoE

  • Käyttäjä
  • Viestejä: 2782
    • Profiili
Vs: Pieni bash scripti kysymys
« Vastaus #3 : 31.01.15 - klo:15.20 »
Ajattelinkin että jotain unohtui - tuo cut-komento. Olen niin paljon tehnyt kaikki perlillä että peruskomennot ovat unohtuneet.

Mutta sitä tulin vielä lisäämään että cut, sort, tail ja sed putkitettuna yhteen eivät mitenkään liity nimenomaan bashiin. Kun nm antaa esimerkin muuttujaan sijoituksesta aletaan olla lähellä, mutta vasta nm:n kolmas esimerkki on puhdasta bash-koodia - äkkivilkaisulla ainoa bashin ulkopuolinen komento siinä on cut.

petteriIII

  • Käyttäjä
  • Viestejä: 693
    • Profiili
Vs: Pieni bash scripti kysymys
« Vastaus #4 : 31.01.15 - klo:18.45 »
Teinpä myöhässä awk-toteutuksen kun en ajoissa huomannut viestiä:
Koodia: [Valitse]
cat ~/tiedosto1 | awk -F ":" '{for(i=1;i<=NF;i++) s[i]+=$i} END {print "sarakesumma=" s[2]}'
- luvut saavat olla desimalisiakin
« Viimeksi muokattu: 31.01.15 - klo:19.59 kirjoittanut petteriIII »

ajaaskel

  • Palvelimen ylläpitäjä
  • Käyttäjä
  • Viestejä: 3401
    • Profiili
Vs: Pieni bash scripti kysymys
« Vastaus #5 : 31.01.15 - klo:21.45 »
Pelkällä Bashillä:   ::)

Koodia: [Valitse]
i=0; while read -r l; do [[ ${l##*:} -gt $i ]] && i=${l##*:}; done <./tiedosto; echo $i3333

Tuo "tiedosto" sisältää nuo rivit jotka mainittiin tehtävässä ja tuolla "$i" muuttujassa on se isoin luku.

Tällä voi tehdä tuon testitiedoston "tiedosto":
Koodia: [Valitse]
cat >./tiedosto <<EOF
abc:1001
def:1002
ghij:1033
klmn:2001
op:2022
qrstu:3333
EOF


eli kopioit tuon päätteeseen.  Joudut painamaan vielä Enter: in ellet onnistunut kopioimaan loppuun asti...
« Viimeksi muokattu: 31.01.15 - klo:22.07 kirjoittanut ajaaskel »
Autamme ilolla ja ilmaiseksi omalla ajallamme.  Ethän vaadi, uhoa tai isottele näin saamasi palvelun johdosta.

tjka

  • Käyttäjä
  • Viestejä: 144
    • Profiili
Vs: Pieni bash scripti kysymys
« Vastaus #6 : 01.02.15 - klo:13.12 »
Kiitos kaikille vastanneille. Nyt pääsen eteenpäin...
Mun tarpeisiin riittää allaoleva oikein hienosti.

suurin=$(cut -d : -f 2 tiedosto.txt | sort -n | tail -n 1)

Tarkoitus on vain tutkia ja päivittää pientä listaa osana toista scriptiä.

-tjka-