Miért tartalmazza az argv a program nevét?

A tipikus Unix / Linux programok elfogadják a parancssori bemeneteket argumentumszámként (int argc) és argumentumvektorként (char *argv[]). A argv első eleme a program neve, amelyet a tényleges argumentumok követnek.

Miért adják át a program nevét argumentumként a futtatható fájlnak? Van néhány példa a saját nevüket használó programokra (esetleg valamilyen exec helyzet)?

Megjegyzések

  • tetszik az mv és a cp?
  • a Debianon sh szimbólum a dash -hez. Másképp viselkednek, amikor sh vagy dash
  • @AlexejMagura néven hívják, ha busybox (mentőlemezeken és hasonlóknál gyakori), akkor nagyjából minden (cp, mv, rm, ls, …) szimbolikus link a busyboxhoz.
  • I ‘ ezt nehezen tudom figyelmen kívül hagyni igazán , ezért ‘ ll mondd ki: valószínűleg ” GNU ” programokra gondolsz (gcc, bash, gunzip, az operációs rendszer többi részének nagy része …), mivel a Linux csak a kernel.
  • @ wizzwizz4 Mi a ‘ hiba a ” tipikus Unix / Linux programokkal “? Úgy olvastam, mint a ” Unix / Linux rendszeren futó tipikus programok “. Ez ‘ sokkal jobb, mint bizonyos GNU programok korlátozása. Dennis Ritchie biztosan nem használt GNU programokat. A BTW A Hurd kernel egy példa egy olyan GNU programra, amely nem rendelkezik fő funkcióval …

Answer

Először is vegye figyelembe, hogy a argv[0] nem feltétlenül a program neve. A hívó ezt helyezi a execve rendszerhívás argv[0] be (pl. Lásd: ezt a kérdést a Verem túlcsordulásáról ). (Az exec összes többi változata nem rendszerhívás, hanem interfész a execve -hez.)

Tegyük fel például, hogy a következő (execl használatával):

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

/var/tmp/mybackdoor amit végrehajtanak, de a argv[0] beállítása top, és ez az, amit ps vagy ( a valós) top jelenik meg. További információkért lásd: ezt a választ az U & L SE oldalon.

Az összes beállítás ezt félretéve: Az olyan divatos fájlrendszerek megjelenése előtt, mint a /proc, a argv[0] volt az egyetlen módja annak, hogy egy folyamat megismerje saját nevét. Mire lenne jó?

  • Számos program testreszabhatja viselkedését attól a névtől függően, amellyel hívták őket (általában szimbolikus vagy kemény linkekkel, például BusyBox segédprogramjai ; erre a kérdésre adott további válaszokban további példákat találunk).
  • Ezenkívül a syslogon keresztül bejelentkező szolgáltatások, démonok és más programok gyakran a nevüket a naplóbejegyzések; enélkül az eseménykövetés a megvalósíthatatlanná válna.

Megjegyzések

  • Ilyen programok például: bunzip2, bzcat és bzip2, amelyek esetében az első kettő szimbólum a harmadikhoz.
  • @Ruslan Érdekes, hogy a zcat nem szimbolikus link. Úgy tűnik, hogy elkerülik ennek a technikának a hátrányait, hanem egy shell parancsfájlt használva. De nem tudnak teljes kimenetet, mert valaki, aki opciókat adott hozzá a gzip-hez, elfelejtette a mainot tain zcat is.
  • Amire csak emlékszem, a GNU kódolási szabványai nem tették lehetővé az argv [0] használatát a program viselkedésének megváltoztatására ( szakasz ” Interfészekre vonatkozó szabványok Általában ” az aktuális verzióban ). A gunzip történelmi kivétel.
  • a busybox egy másik kiváló példa. 308 különböző névvel hívható meg különböző parancsok meghívására: busybox.net/downloads/BusyBox.html#commands
  • sok, sok több program a argv[0] jüket is beinjektálja a használati / súgó kimenetbe ahelyett, hogy keményen kódolná a nevét. Van, aki teljes egészében, van, akinek csak a basename.

Válasz

Rengeteg:

  • A Bash POSIX módban fut, amikor a argv[0] sh. Bejelentkezési héjként fut, amikor a argv[0] - karakterrel kezdődik.
  • A Vim másként viselkedik, amikor vi, view, evim, eview, ex, vimdiff stb.
  • Busybox, mint már említettük.
  • Azokban a rendszerekben, ahol a systemd az init, shutdown, reboot stb. a systemctl -re mutat.
  • és így tovább.

Megjegyzések

  • Egy másik a sendmail és a mail. Minden egyes unix MTA-hoz tartozik egy szimbolikus link a két parancshoz, és úgy lett kialakítva, hogy az eredeti ‘ viselkedését utánozza, amikor ilyennek hívják, vagyis minden unix program, amelynek e-mailt kell küldenie pontosan hogyan tudják ezt megtenni.
  • egy másik gyakori eset: test és [: amikor előbbit hívja , akkor kezel hibát, ha az utolsó argumentum ]. (a tényleges Debian stabilnál ezek a parancsok két különböző programot jelentenek, de a korábbi verziók és a MacO továbbra is ugyanazt a programot használják). És tex, latex és így tovább: a bináris ugyanaz, de nézve, hogy hívták, a megfelelő konfiguráció fájl. A init hasonló.
  • Kapcsolódó, a [ hibának tartja, ha az utolsó argumentum nem ].
  • Azt hiszem, ez a második kérdésre ad választ, de az elsőre nem. Nagyon kétlem, hogy valamelyik operációs rendszert tervező leült volna, és azt mondta » Hé, jó lenne, ha ugyanaz a program csinálnék különböző dolgokat, csak a futtatható neve alapján. Azt hiszem, ‘ majd belefoglalom a nevet az argumentumtömbjébe, majd. «
  • @Joey Igen, a a megfogalmazás azt hivatott közvetíteni, hogy (Q: ” Van-e …? ” A: ” Rengeteg: … “)

Válasz

Történelmileg a argv csak a parancssor “szavai” -ra mutató mutatók tömbje, ezért van értelme az első “szóval” kezdeni, amely történetesen a A program neve.

És van néhány olyan program, amelyek eltérően viselkednek attól függően, hogy melyik név alapján hívják őket, így egyszerűen létrehozhat hozzájuk különböző linkeket, és különböző “parancsokat” kaphat. a legszélsőségesebb példa, amelyre gondolok, az a busybox , amely úgy működik, mint több tucat különböző “parancs”, attól függően, hogy a neve .

Szerkesztés

: Hivatkozások az Unix 1. kiadására, igény szerint

Látható pl. a cc main függvényéből, hogy argc és argv már használatban volt. A shell az argumentumokat átmásolja a parbuf fájlba a newarg részen belül. a ciklust, miközben magát a parancsot ugyanúgy kezeli, mint az argumentumokat. (Természetesen a későbbiekben csak az első argumentumot hajtja végre, amely a parancs neve). Úgy tűnik, hogy execv és a rokonok akkor még nem léteztek.

Megjegyzések

  • kérjük, adjon hozzá olyan hivatkozásokat, amelyek alátámasztja ezt.
  • Gyors átugrással a exec felveszi a végrehajtandó parancs nevét és egy nulla végű karakterjelet (tömb a legjobban a div id = “543ef4ed88”> minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , ahol exec hivatkozásokat vesz a 2. és az 1. címkére, és a 2: címkénél megjelenik etc/init\0, és az 1: hivatkozás a 2. címkére és egy végződő nulla) jelenik meg, amit alapvetően execve tesz ma mínusz envp.
  • execv és execl léteztek ” örökre ” (azaz az 1970-es évek elejétől közepéig) – execv rendszerhívás volt, és könyvtárfunkció volt, amely hívta. execve nem létezett akkor, mert a környezet akkor még nem létezett ‘. A család többi tagját később hozzáadták.
  • @ G-Man Tudna rám utalni execv -re az általam linkelt v1-forrásban? Csak kíváncsi.

Válasz

Felhasználási esetek:

A program nevével módosíthatja a program viselkedését .

Például létrehozhat néhány hivatkozást az aktuális bináris fájlra.

Az egyik leghíresebb példa erre a technikára a busybox projekt, amely csak egyetlen bináris programot telepít, és sok szinkronizálást. (ls, cp, mv stb.). azért teszik, hogy tárhelyet takarítsanak meg , mert célpontjaik kicsi beágyazott eszközök.

Ez is használt setarch fájlban a util-linuxból:

$ 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 

Itt ezt a technikát használják alapvetően sok duplikált forrásfájl elkerülése érdekében vagy csak a források olvashatóbbá tétele érdekében.

Egy másik felhasználási eset egy olyan program lenne, amelyre szüksége van néhány modult vagy adatot futás közben betölteni. A program elérési útja lehetővé teszi számára, hogy modulokat töltsön be egy útvonalról a program helyéhez viszonyítva .

Ezenkívül számos program hibaüzenetet nyomtat, beleértve a program nevét .

Miért :

  1. Mivel ez a POSIX konvenció ( man 3p execve):

Az argv az új programnak átadott argumentumláncok tömbje. Megállapodás szerint az első ilyen karakterláncnak tartalmaznia kell a végrehajtandó fájlhoz társított fájlnevet.

  1. It “s C standard (legalább C99 és C11):

Ha az argc értéke nagyobb, mint nulla, akkor az argv [0] ] a program nevét jelöli; Az argv [0] [0] lesz a null karakter, ha a program neve nem érhető el a hosztkörnyezetből.

Ne feledje, hogy a C szabvány azt mondja: “program név “nem” fájlnév “.

Megjegyzések

  • Nem történik meg ‘ t ez a törés, ha eléri a symlink egy másik symlinktől?
  • @Mehrdad, Igen, ez ‘ hátránya, és zavaró lehet a felhasználó számára.
  • @rudimeier: ‘ A ‘ miért nem igazán ok, hanem ‘ csak egy ” homunculus “, vagyis csak felveti a kérdést, miért követeli meg a szabvány ezt.
  • @ einpoklum OP ‘ kérdés a következő volt: Miért adják át a program nevét a futtatható fájlnak? Azt válaszoltam: Mivel a POSIX és a C szabvány ezt mondja meg nekünk. Hogyan gondolja, hogy a ‘ nem valójában oka ? Ha az általam idézett dokumentumok nem léteznének, akkor valószínűleg sok program nem adná át a program nevét.
  • Az OP hatékonyan kéri a következőt: ” MIÉRT mondják ezt a POSIX és C szabványok? ” Megengedett, hogy a megfogalmazás elvont szintű legyen, de egyértelműnek tűnik. Valójában az egyetlen módja annak megismerése, hogy megkérdezzük a kezdeményezőket.

Válasz

Amellett, hogy a programok megváltoztatják a programjukat viselkedésük attól függően, hogy hívták őket, a argv[0] programot hasznosnak találom egy program használatának kinyomtatásában, például:

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

Ez azt eredményezi, hogy a használati üzenet mindig azt a nevet használja, amelyen keresztül hívták. Ha a programot átnevezik, a használati üzenete ezzel együtt változik. Még az elérési út nevét is tartalmazza, amellyel hívták:

# 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] 

Ez kellemes tapintású, különösen kis, speciális célú eszközök / szkriptek esetében, amelyek mindenütt élhetnek a hely.

Ez a GNU eszközökben is általános gyakorlatnak tűnik, lásd például: ls:

% 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. 

megjegyzések

  • +1. Ugyanezt javasoltam. Furcsa, hogy olyan sok ember a viselkedés megváltoztatására koncentrál, és nem említi a valószínűleg legkézenfekvőbb és sokkal szélesebb körű használat.

Válasz

Az egyik végrehajtja a program beírását: program_name0 arg1 arg2 arg3 ....

Tehát a shellnek már el kell osztania a tokent, és az első token már a program neve. És BTW, így ugyanazok az indexek vannak a program oldalán és a shellen.

Úgy gondolom, hogy ez csak egy kényelmi trükk volt (a legelején), és mint más válaszokban láthatja, ez is nagyon hasznos volt, ezért ezt a hagyományt folytatták és et mint API.

Válasz

Alapvetően az argv tartalmazza a program nevét, így olyan hibaüzeneteket írhat, mint prgm: file: No such file or directory, amely ilyesmivel valósulna meg:

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

Válasz

Ennek az alkalmazásnak egy másik példája ez a program, amely önmagával … helyébe lép, amíg be nem ír valami, ami nem “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; } 

Nyilvánvalóan egyfajta kitalált, ha érdekes példa, de úgy gondolom, hogy ennek valódi felhasználása lehet – például egy önfrissítő bináris, amely újraírja saját memóriaterülete egy új verzióval, amelyet letöltött vagy módosított.

Példa:

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

Forrás és további információk .

Megjegyzések

  • Gratulálunk az 1000 eléréséhez.

Válasz

A program elérési útja argv[0], így a program képes beolvasni a konfigurációs fájlokat stb. a telepítési könyvtárból.
Ez lehetetlen lenne argv[0] nélkül.

Megjegyzések

  • Ez ‘ nem különösebben jó magyarázat – nincs ‘ semmi ok, amiért nem tudnánk ‘ nem szabványosítottak például (char *path_to_program, char **argv, int argc), például
  • Afaik, a legtöbb program a konfigurációt normál helyről húzza le (~/.<program>, /etc/<program, $XDG_CONFIG_HOME ), vagy válasszon egy paramétert annak megváltoztatásához, vagy rendelkezzen olyan fordítási idő opcióval, amely konstansban süt a bináris értékre.

Válasz

ccache így viselkedik az utánzás érdekében különböző hívások a fordító bináris fájljaira. A ccache egy fordító gyorsítótár – az a lényeg, hogy soha ne fordítsuk le ugyanazt a forráskódot kétszer, hanem lehetőség szerint visszaadjuk az objektumkódot a gyorsítótárból.

A ccache man page , “a ccache használatának kétféle módja van. A fordítási parancsokat előtagolhatja a ccache-el, vagy hagyhatja, hogy a ccache leforduljon fordítóként, ha létrehoz egy szimbolikus linket (amelyet fordítónak hívnak) a ccache-re. Az első módszer a legkényelmesebb, ha csak a ccache-t szeretné kipróbálni, vagy néhány konkrét projekthez szeretné használni. A második módszer akkor a leghasznosabb, amikor a ccache-t szeretné használni az összes összeállításához. “

A A symlinks módszer a következő parancsok futtatását foglalja magában:

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 ... 

… amelynek eredményeként a ccache lehetővé teszi, hogy elkapjon minden olyan parancsot, amely egyébként a fordítókhoz került volna, így a ccache lehetővé teszi a gyorsítótárazott fájl visszaadását vagy a parancs továbbadását a tényleges fordítónak.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük