Miksi argv sisältää ohjelman nimen?

Tyypilliset Unix / Linux-ohjelmat hyväksyvät komentorivin syötteet argumenttien määränä (int argc) ja argumenttivektorina (char *argv[]). argv -elementin ensimmäinen elementti on ohjelman nimi, jota seuraavat todelliset argumentit.

Miksi ohjelman nimi välitetään suoritettavalle tiedostolle argumenttina? Onko olemassa esimerkkejä ohjelmista, jotka käyttävät omaa nimeään (ehkä jonkinlainen exec tilanne)?

Kommentit

  • kuten mv ja cp?
  • Debianissa sh on symlinkki dash. He käyttäytyvät eri tavalla, kun niitä kutsutaan nimellä sh tai nimellä dash
  • @AlexejMagura Jos käytät jotain busybox (yleinen pelastuslevyillä ja vastaavilla), niin melkein kaikki (cp, mv, rm, ls, …) on symbolinen linkki väylälaatikkoon.
  • I ’ minusta on todella vaikea sivuuttaa, joten ’ ll sano se: tarkoitat todennäköisesti ” GNU ” -ohjelmia (gcc, bash, gunzip, suurin osa muusta käyttöjärjestelmästä …), koska Linux on vain ydin.
  • @ wizzwizz4 Mitä ’ vikaa ” tyypillisillä Unix / Linux-ohjelmilla ”? Luin sen kuten ” Tyypilliset Unix / Linux-ohjelmat ”. Se ’ on paljon parempi kuin rajoituksesi tiettyihin GNU-ohjelmiin. Dennis Ritchie ei todellakaan käyttänyt mitään GNU-ohjelmia. BTW Hurd -ydin on esimerkki GNU-ohjelmasta, jolla ei ole päätoimintoa …

Answer

Huomaa aluksi, että argv[0] ei välttämättä ole ohjelman nimi. Soittaja asettaa tämän execve -järjestelmäkutsun argv[0] -sarjaan (esim. Katso tämä kysymys pinon ylivuotoa ). (Kaikki muut versiot exec eivät ole järjestelmäkutsuja, vaan liitännät ryhmään execve.)

Oletetaan esimerkiksi, että seuraava (käyttäen execl):

execl("/var/tmp/mybackdoor", "top", NULL); 

/var/tmp/mybackdoor on mikä suoritetaan, mutta argv[0] -asetuksena on top, ja tämä on ps tai ( todellinen) top näytetään. Katso tämä vastaus U & L SE: ltä.

Kaikkien asetusten määrittäminen tämä syrjään: Ennen hienojen tiedostojärjestelmien, kuten /proc, syntymistä argv[0] oli ainoa tapa prosessille oppia omasta nimestään. Mille se olisi hyvä?

  • Useat ohjelmat mukauttavat käyttäytymistään nimen mukaan, jolla niitä kutsuttiin (yleensä symbolisilla tai kovilla linkeillä, esimerkiksi / div> BusyBoxin apuohjelmat ; useita muita esimerkkejä annetaan muissa vastauksissa tähän kysymykseen).
  • Lisäksi syslogin kautta kirjautuvat palvelut, demonit ja muut ohjelmat usein liittävät nimensä lokimerkinnät; ilman tätä tapahtumien seuranta olisi mahdotonta.

Kommentit

  • Esimerkkejä tällaisista ohjelmista ovat bunzip2, bzcat ja bzip2, joista kaksi ensimmäistä ovat linkkejä kolmanteen.
  • @Ruslan Mielenkiintoista, että zcat ei ole symboli. He näyttävät välttävän tämän tekniikan haittoja käyttämällä komentotulkkikomentosarjaa. Mutta he eivät pysty tulostamaan täydellistä --help -lähtö, koska joku, joka lisäsi vaihtoehtoja gzip-tiedostoon, unohti pääsivun tain zcat.
  • Niin kauan kuin muistan, GNU-koodausstandardit ovat estäneet argv [0]: n käyttöä ohjelman käyttäytymisen muuttamiseksi ( -osio ” Liitäntöjen standardit Yleensä ” nykyisessä versiossa ). gunzip on historiallinen poikkeus.
  • busybox on toinen erinomainen esimerkki. Sitä voidaan kutsua 308 eri nimellä kutsumaan erilaisia komentoja: busybox.net/downloads/BusyBox.html#commands
  • monia, monia useampia ohjelmia myös injektoidaan argv[0] käyttö- / ohjetulosteeseen nimen koodaamisen sijaan. Jotkut kokonaan, jotkut vain basename.

Vastaa

Runsaasti:

  • Bash toimii POSIX-tilassa , kun argv[0] on sh. Se toimii kirjautumiskuorena, kun argv[0] alkaa -.
  • Vim käyttäytyy eri tavalla, kun sitä käytetään nimellä vi, view, evim, eview, ex, vimdiff jne.
  • Busybox, kuten jo mainittiin.
  • Järjestelmissä, joissa systemd on init, shutdown, reboot jne. Ovat symboloi systemctl .
  • ja niin edelleen.

Kommentit

  • Toinen on sendmail ja mail. Jokaisessa yksittäisessä unix MTA: ssa on symlinkki näille kahdelle komennolle, ja se on suunniteltu jäljittelemään alkuperäistä ’ käyttäytymistä, kun sitä kutsutaan sellaisenaan, mikä tarkoittaa, että kaikki unix-ohjelmat, joiden on lähetettävä sähköpostia, tietävät miten he voivat tehdä niin.
  • toinen yleinen tapaus: test ja [: kun soitat edelliseen , se käsittelee virheen, jos viimeinen argumentti on ]. (todellisessa Debianin vakaa tilassa nämä komennot ovat kahta erilaista ohjelmaa, mutta aiemmat versiot ja MacO: t käyttävät edelleen samaa ohjelmaa). Ja tex, latex ja niin edelleen: binääri on sama, mutta katsoen kuinka sitä kutsuttiin, se valitsee oikean kokoonpano tiedosto. init on samanlainen.
  • Related, [ pitää virhenä, jos viimeinen argumentti on ei ].
  • Luulen, että tämä vastaa toiseen kysymykseen, mutta ei ensimmäiseen. Epäilen kovasti, että joku käyttöjärjestelmän suunnittelija istui alas ja sanoi » Hei, olisi hienoa, jos minulla olisi sama ohjelma, joka tekisi erilaisia asioita vain sen suoritettavan nimen perusteella. Luulen, että ’ sisällytän nimen sitten argumenttiryhmäänsä. «
  • @Joey Kyllä, sanamuoto on tarkoitettu välittämään, että (Q: ” Onko …? ” A: ” Runsaasti: … ”)

vastaus

Historiallisesti argv on vain joukko osoittimia komentorivin ”sanoille”, joten on järkevää aloittaa ensimmäisellä ”sanalla”, joka satunnaisesti on ohjelman nimi.

Ja on olemassa melko monta ohjelmaa, jotka käyttäytyvät eri tavalla sen mukaan, minkä nimen avulla niitä kutsutaan, joten voit luoda vain erilaisia linkkejä niihin ja saada erilaisia ”komentoja”. äärimmäinen esimerkki, jonka voin ajatella, on väylälaatikko , joka toimii kuin useita kymmeniä erilaisia ”komentoja” sen mukaan, miten sitä kutsutaan .

Muokkaa

: Viitteet Unixin 1. painokseen pyydettäessä

Näet esimerkiksi cc -toiminnon tärkeimmistä funktioista, jotka argc ja argv oli jo käytetty. -kuori kopioi argumentit parbuf -kansioon newarg -osan sisällä silmukkaa, kun taas itse komentoa käsitellään samalla tavalla kuin argumentteja. (Tietenkin myöhemmin se suorittaa vain ensimmäisen argumentin, joka on komennon nimi.) Näyttää siltä, että execv ja sukulaisia ei ollut silloin.

Kommentit

  • lisää viitteet, jotka varmuuskopioi tämä.
  • Nopeasta skoimisesta exec ottaa suoritettavan komennon nimen ja nollapäätteisen taulukon merkkijonoja (näkyy parhaiten kohdassa minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , missä exec vie viitteet tunnisteisiin 2 ja 1 ja tunnisteissa 2: näkyy etc/init\0 ja tunnisteissa 1: näyttää viitteen tunnisteeseen 2 ja päättyvän nollan), mikä on periaatteessa mitä execve tekee tänään miinus envp.
  • execv ja execl ovat olleet olemassa ” ikuisesti ” (ts. 1970-luvun alusta puoliväliin) – execv oli järjestelmäkutsu ja oli kirjastotoiminto, joka kutsui sitä. Tällöin execve ei ollut olemassa ’, koska ympäristöä ei ollut silloin olemassa ’. Muut perheenjäsenet lisättiin myöhemmin.
  • @ G-Man Voitteko osoittaa minut execv linkittämääni v1-lähteeseen? Vain utelias.

Vastaa

Käyttötapaukset:

Voit käyttää ohjelman nimeä ohjelman käyttäytymisen muuttamiseen .

Voit esimerkiksi luoda joitain symboleita varsinaiseen binaariin.

Yksi tunnetuimmista esimerkeistä, joissa tätä tekniikkaa käytetään, on busybox-projekti, joka asentaa vain yhden yksittäisen binaarin ja useita symboleita siihen. (ls, cp, mv jne.). He tekevät sen säästääkseen tallennustilaa , koska niiden kohteet ovat pieniä upotettuja laitteita.

Tämä on myös käytetään setarch -sovelluksessa util-linuxista:

$ ls -l /usr/bin/ | grep setarch lrwxrwxrwx 1 root root 7 2015-11-05 02:15 i386 -> setarch lrwxrwxrwx 1 root root 7 2015-11-05 02:15 linux32 -> setarch lrwxrwxrwx 1 root root 7 2015-11-05 02:15 linux64 -> setarch -rwxr-xr-x 1 root root 14680 2015-10-22 16:54 setarch lrwxrwxrwx 1 root root 7 2015-11-05 02:15 x86_64 -> setarch 

Tässä he käyttävät tätä tekniikkaa pohjimmiltaan välttääksesi useita päällekkäisiä lähdetiedostoja tai vain pitääkseen lähteet helpommin luettavissa.

Toinen käyttötapaus olisi ohjelma, joka tarvitsee ladata joitain moduuleja tai tietoja ajon aikana. Ohjelmapolun saaminen antaa sinun ladata moduuleja polulta suhteessa ohjelman sijaintiin .

Lisäksi monet ohjelmat tulostavat virheilmoitukset, mukaan lukien ohjelman nimi .

Miksi :

  1. Koska se on POSIX-käytäntö ( man 3p execve):

argv on joukko argumenttijonoja, jotka välitetään uudelle ohjelmalle. Sopimuksen mukaan ensimmäisen näistä merkkijonoista tulisi sisältää suoritettavaan tiedostoon liittyvä tiedostonimi.

  1. Se C vakio (vähintään C99 ja C11):

Jos argc-arvo on suurempi kuin nolla, merkkijono, johon argv viittaa [0 ] edustaa ohjelman nimeä; argv [0] [0] on tyhjä merkki, jos ohjelman nimeä ei ole saatavana isäntäympäristöstä.

Huomaa, että C-standardi sanoo ”ohjelma nimi ”ei” tiedostonimi ”.

Kommentit

  • Ei ’ t tätä taukoa, jos saavut symlink toisesta symlinkistä?
  • @Mehrdad, Kyllä, ’ on haittapuoli ja voi olla hämmentävää käyttäjälle.
  • @rudimeier: ’ Miksi ’ -kohteet eivät ole oikeastaan syitä, ne ’ ovat vain ” homunculus ”, eli se vain herättää kysymyksen, miksi standardi vaatii tämän olevan asia.
  • @ einpoklum OP ’ -kysymys oli: Miksi ohjelman nimi välitetään suoritettavalle tiedostolle? Vastasin: Koska POSIX- ja C-standardit käskevät meitä tekemään niin. Kuinka luulet, että ’ ei ole oikeastaan syy ? Jos lainaamiasi asiakirjoja, joita

olen lainannut, ei todennäköisesti olisi, monet ohjelmat eivät välittäisi ohjelman nimeä.

  • OP kysyy tehokkaasti ” MIKSI POSIX- ja C-standardit sanovat tämän tekevän? ” Sanottiin, että sanamuoto oli abstraktilla tasolla, mutta se näyttää selkeältä. Realistisesti ainoa tapa tietää on kysyä tekijöiltä.
  • Vastaa

    Sen lisäksi, että ohjelmat muuttavat heidän ohjelmiaan käyttäytyminen sen mukaan, miten heitä kutsuttiin, mielestäni argv[0] on hyödyllinen ohjelman käytön tulostamisessa, kuten:

    printf("Usage: %s [arguments]\n", argv[0]); 

    Tämän vuoksi käyttöviestissä käytetään aina nimeä, jolla sitä kutsuttiin. Jos ohjelma nimetään uudelleen, sen käyttöviesti muuttuu sen mukana. Se sisältää jopa polun nimen, jolla sitä kutsuttiin:

    # cat foo.c #include <stdio.h> int main(int argc, char **argv) { printf("Usage: %s [arguments]\n", argv[0]); } # gcc -Wall -o foo foo.c # mv foo /usr/bin # cd /usr/bin # ln -s foo bar # foo Usage: foo [arguments] # bar Usage: bar [arguments] # ./foo Usage: ./foo [arguments] # /usr/bin/foo Usage: /usr/bin/foo [arguments] 

    Se on mukava kosketus, erityisesti pienille erikoistyökaluille / skripteille, jotka saattavat elää kaikkialla paikka.

    Tämä näyttää olevan yleinen käytäntö myös GNU-työkaluissa, katso ls esimerkiksi:

    % ls --qq ls: unrecognized option "--qq" Try "ls --help" for more information. % /bin/ls --qq /bin/ls: unrecognized option "--qq" Try "/bin/ls --help" for more information. 

    kommentit

    • +1. Aioin ehdottaa samaa. Kummallista, että niin monet ihmiset keskittyvät käyttäytymisen muuttamiseen eivätkä mainitse luultavasti ilmeisimpiä ja paljon laajempi käyttö.

    Vastaus

    Yksi suorittaa ohjelman kirjoittamisen: program_name0 arg1 arg2 arg3 ....

    Joten kuoren pitäisi jo jakaa tunnus, ja ensimmäinen merkki on jo ohjelman nimi. Ja BTW, joten ohjelmapuolella ja kuoressa on samat indeksit.

    Luulen, että tämä oli vain mukavuuden temppu (aivan alusta alkaen), ja kuten näette muissa vastauksissa, se oli myös erittäin kätevä, joten tätä perinnettä jatkettiin ja s et API: na.

    Vastaus

    Pohjimmiltaan argv sisältää ohjelman nimen, jotta voit kirjoittaa virheilmoituksia, kuten prgm: file: No such file or directory, joka toteutetaan tällä tavoin:

     fprintf( stderr, "%s: %s: No such file or directory\n", argv[0], argv[1] ); 

    Vastaa

    Toinen esimerkki tämän sovelluksesta on tämä ohjelma, joka korvaa itsensä … itsellä, kunnes kirjoitat jotain, joka ei ole ”t y.

    #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char** argv) { (void) argc; printf("arg: %s\n", argv[1]); int count = atoi(argv[1]); if ( getchar() == "y" ) { ++count; char buf[20]; sprintf(buf, "%d", count); char* newargv[3]; newargv[0] = argv[0]; newargv[1] = buf; newargv[2] = NULL; execve(argv[0], newargv, NULL); } return count; } 

    On selvää, että keksitty, joskin mielenkiintoinen esimerkki, mutta mielestäni tällä voi olla todellisia käyttötarkoituksia – esimerkiksi itse päivittyvä binääri, joka kirjoittaa uudestaan oma muistitila ja uusi versio itsestä, jonka se ladasi tai muutti.

    Esimerkki:

    $ ./res 1 arg: 1 y arg: 2 y arg: 3 y arg: 4 y arg: 5 y arg: 6 y arg: 7 n 7 | $ 

    Lähde ja lisätietoja .

    Kommentit

    • Onnittelut 1000: n saavuttamisesta.

    vastaus

    Ohjelman polku on argv[0], jotta ohjelma voi noutaa kokoonpanotiedostot jne. sen asennushakemistosta.
    Tämä olisi mahdotonta ilman argv[0].

    Kommentit

    • Että ’ ei ole erityisen hyvä selitys – siellä ’ ei ole mitään syytä, miksi emme voineet ’ t eivät ole standardoineet esimerkiksi (char *path_to_program, char **argv, int argc), esimerkiksi
    • Afaik, useimmat ohjelmat hakevat kokoonpanoa vakiopaikasta (~/.<program>, /etc/<program, $XDG_CONFIG_HOME ) ja joko ota parametri muuttaaksesi sitä tai sinulla on käännösaika-vaihtoehto, joka leipoo vakiona binaariin.

    vastaus

    ccache käyttäytyy tällä tavalla jäljittelemään eri puhelut kääntäjän binääreille. ccache on kokoamisvälimuisti – koko kohta ei ole koskaan koota samaa lähdekoodia kahdesti, vaan palauttaa objektikoodi välimuistista, jos mahdollista.

    Kohdasta ccache man page , ”ccache-tiedostoa voi käyttää kahdella tavalla. Voit joko etuliittää kokoamiskomennot ccachella tai antaa ccache-maskin kääntäjänä luomalla symbolisen linkin (nimeltä kääntäjä) ccache-välimuistiin. ensimmäinen menetelmä on kätevin, jos haluat vain kokeilla ccache-muistia tai haluat käyttää sitä joissakin tietyissä projekteissa. Toinen menetelmä on hyödyllisin silloin, kun haluat käyttää ccache-tiedostoa kaikissa kokoelmissasi. ”

    symlinks-menetelmä sisältää näiden komentojen suorittamisen:

    cp ccache /usr/local/bin/ ln -s ccache /usr/local/bin/gcc ln -s ccache /usr/local/bin/g++ ln -s ccache /usr/local/bin/cc ln -s ccache /usr/local/bin/c++ ... etc ... 

    … jonka seurauksena ccache sallii tarttua komentoihin, jotka muuten olisivat menneet kääntäjille, Näin ccache voi palauttaa välimuistitiedoston tai välittää komennon todelliselle kääntäjälle.

    Vastaa

    Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *