NAME getopt - Parse command line options SYNOPSIS #include < unistd.h> int getopt(int argc, char * const argv[], const char *optstring); extern char *optarg; extern int optind, opterr, optopt;Komennolle annetaan parametrina mainin saamat argc- ja argv-muuttujat sekä merkkijono, joka kertoo mitä komentorivioptioita ohjelma voi saada. getoptin käyttö vaikuttaa myös automaattisesti ohjelmaan mukaan liitettäviin globaaleihin muuttujiin optarg, optind, opterr ja optopt. Seuraavassa ote ohjelmasta 3-1.c:
int optio; while( 1 ){ optio = getopt(argc, argv, ":abc"); if ( optio == -1 ) break; switch ( optio ){ case 'a': printf(" optio a\n"); break; case 'b': printf(" optio b\n"); break; case 'c': printf(" optio c\n"); break; case '?': printf(" tuntematon optio %c \n", optopt); break; } }Optioiden käsittely kannattaa suorittaa toistuvasti getoptia kutsuvassa while-loopissa. getoptin kolmantena parametrinä on ":abc", joka tarkoittaa sitä, että ohjelman mahdolliset optiot ovat a, b ja c. Alussa oleva : laittaa getoptin toimimaan siten, että se ei tulosta automaattisesti virheilmoituksia.
getopt toimii siten, että se skannaa läpi ohjelman komentoriviparametrit ja etsii niiden joukosta halutut optiot. getopt palauttaa arvonaan -1 siinä vaiheessa kun kaikki optiot on etsitty tai jos optioita ei ole. Jos löytyy tuntematon optio, on paluuarvo '?', muuten paluuarvo on löytynyt optio.
Jos löydetään tuntematon optio, saa globaali muuttuja optopt arvokseen tuntemattoman option. Yllä oleva ohjelmanpätkä printtaa virheilmoituksena tuntemattoman option käyttäen optopt-muuttujaa.
Optiot saa syöttää ohjelmalle missä järjestyksessä tahansa, ja väliin saa sijoittaa muita komentoriviparametrejä. getopt toimii joka tapauksessa
Seuraavassa tilanne, missä annettu komento ls testi -l -a sekä heti ohjelman käynnistyessä, että getopt-loopin suorituksen jälkeen.
Seuraavassa ohjelman 3-1.c loppuosa, joka tulostaa optioiden käsittelyn jälkeen ohjelman muut komentoriviparametrit.
if ( optind < argc){ printf("\nloput komentoriviparametrit:\n"); int i; for ( i=optind; i < argc; i++) printf("% s\n",argv[i]); } else { printf("\nei komentoriviparametrejä\n"); }Ohjelman on yleensä muistettava mitä optioita sille on annettu. Yksi keino hoitaa optioiden muistaminen on yksinkertaisten muuttujien käyttö siten, että esim. muuttujan aflag arvo on 1 jos optio a on annettu ja muuten aflag:n arvo on 0. Ohjelma 3-2.c demonstroi flagien asettamista.
Ohjelman "normaalia laskentaa" ei koskaan kannata suorittaa getopt-loopissa. Eli järkevintä on toimia siten, että getopt-loopissa kerätään tieto siitä mitä optioita ohjelmalla on. Tämän jälkeen vasta aloitetaan ohjelman normaali toiminta.
[luuma@telinux1 vko3]$ ssh 192.168.181.18 -l mluukkai mluukkai@192.168.181.18's password:Option ja argumentin välissä ei ole pakko olla välilyöntiä.
Myös argumentillisten optioiden tunnistaminen hoituu getioptilla. Ohjelmalla 3-3.c voi olla optiot a ja b. Optiolla b on argumentti. Ote optiot käsittelevästä koodista:
char *b_arg; // osoitin b option argumenttiin while( optio = getopt(argc, argv, ":ab:") ){ if ( optio == -1 ) break; // ei enää optioita, jatketaan switch ( optio ){ case 'b': bflag = 1; // optarg osoittaa argumenttiin b_arg = optarg; // otetaan osoitin talteen break; case ':': // option argumentti puuttuu printf(" optiolla %c on oltava argumentti\n", optopt); break; ...optargin kolmas parametri on muotoa ":ab:", kaksoispiste option b jälkeen kertoo, että b:llä on argumentti. getopt:in palautaessa b, globaali muuttuja obtarg osoittaa option argumenttia (eli käytännössä jotain merkkijonoista argv[1], argv[2], ... ). Osoitin argumenttiin otetaan talteen b:n case-haarassa. Jos b annetaan ilman argumenttia, palauttaa optget arvon ':', tälle tehdään oma case-haara joka tulostaa virheilmoituksen.
Terminaalin toimintaan voi vaikuttaa käyttämällä termios.h-kirjaston tarjoamia funktioita, meille näistä riittävät seuraavat:
#include < termios.h> #include < unistd.h> int tcgetattr(int fd, struct termios *termios_p); int tcsetattr(int fd, int optional_actions, struct termios *termios_p);Funktiot käyttävät tietuetta struct termios. Tietueella on useita kenttiä, mutta yleensä kentät c_lflags ja c_cc riittävät. struct termios on siis määritelty suunnileen seuraavasti:
struct termios{ tcflag_t c_lflag; cc_t c_cc[NCCS]; ... // jotain muita kenttiä };Ohjelma 3-4.c ottaa hetkeksi merkkien ruudulle kaiuttamisen pois päältä. Ote ohjelmakoodista:
int main(){ struct termios vanha, uusi; char buf[80]; // otetaan terminaalin toimintamoodin tiedot muuttujaan vanha // fileno(stdin) tarkoittaa standardisyötettä eli näppäimistöä // vastaavaa tiedostokuvaajaa tcgetattr( fileno(stdin), &vanha ); // kopioidaan oletusasetukset muuttujaan uusi uusi = vanha; // kytketään kirjoitettujen merkkien kaiutus pois päältä uusi.c_lflag = uusi.c_lflag & ~ECHO; // asetetaan terminaalille uusi toimintamoodi tcsetattr( fileno(stdin), TCSANOW, &uusi ); printf("anna syöte: "); fgets(buf, 80, stdin); printf("\nkirjoitit: %s", buf); // palautetaan vanha toimintamoodi tcsetattr( fileno(stdin), TCSANOW, &vanha );struct termios:in c_lflag-kenttä koostuu joukosta terminaalin toimintamoodia ohjaavista flageja jotka joko ovat päällä tai poissa. Ohjelmassa otetaan ECHO-flagi pois päältä. Tämä tapahtuu tekemällä and-operaatio (eli &) flagien arvolle sekä ECHO-flagin negaatiolle ~ECHO:
uusi.c_lflag = uusi.c_lflag & ~ECHO;Yleisemmin, flagin XXX saa päälle tekemällä or-operaation (eli |):
uusi.c_lflag = uusi.c_lflag | XXX;ja pois päältä and-operaatiolla ja negaatiolla:
uusi.c_lflag = uusi.c_lflag & ~XXX;Ohjelma 3-5.c ottaa kaiutuksen pois ja siirtyy merkeittäin tapahtuvaan terminaalin käsittelyyn. Ote ohjelmasta:
// otetaan terminaalin toimintamoodin tiedot muuttujaan vanha tcgetattr( fileno(stdin), &vanha ); // kytketään kirjoitettujen merkkien kaiutus pois päältä uusi.c_lflag = uusi.c_lflag & ~ECHO; // lopetetaan syötteen käsittely riveittäin uusi.c_lflag = uusi.c_lflag & ~ICANON; // luetaan merkkejä yksitellen uusi.c_lflag = uusi.c_cc[VMIN] = 1; // odotetaan jokaista merkkiä niin kauan kunnes merkki syötetty uusi.c_lflag = uusi.c_cc[VTIME] = 0; // VTIME-arvo tarkoittaa aikaa, miten kauan yhtä merkkiä odotetaan // arvo 0 tarkoittaa, että merkkiä odotetaan niin kauan kunnes merkki on syötetty // asetetaan terminaalille uusi toimintamoodi tcsetattr( fileno(stdin), TCSANOW, &uusi ); printf("paina jotain, niin aloitetaan\n"); getchar();Syötettyjen merkkien tallentaminen on huolehdittava nyt itse, eli syötetyt merkit kootaan char-taulukkoon buf, johon lopuksi laitetaan \0-merkki merkkijonon päättymisen merkiksi.Ohjelma aloittaa asettamalla uuden terminaalimoodin, jossa kaiutus ja ICANON ovat poissa päältä. ICANON tarkoittaa riveittäistä käsittelyä. Ohjelma lukee yhden merkin käyttäjältä käyttäen getchar-funktiota. Tämän jälkeen ohjelma menee loopiin, jossa luetaan merkkejä kunnes annetaan enter:i = 0; printf("syötä tekstiä, lopetus enter\n"); while( 1 ){ c = getchar(); if ( c == '\n' ) break; buf[i] = c; i++; } buf[i] = '\0'; printf("syöte oli: %s\n", buf);