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
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
ésbzip2
, 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 aargv[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. asystemctl
-re mutat. - és így tovább.
Megjegyzések
- Egy másik a
sendmail
és amail
. 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). Éstex
,latex
és így tovább: a bináris ugyanaz, de nézve, hogy hívták, a megfelelő konfiguráció fájl. Ainit
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 , aholexec
hivatkozásokat vesz a 2. és az 1. címkére, és a2:
címkénél megjeleniketc/init\0
, és az1:
hivatkozás a 2. címkére és egy végződő nulla) jelenik meg, amit alapvetőenexecve
tesz ma mínuszenvp
. -
execv
ésexecl
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 :
- 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.
- 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.
sh
szimbólum adash
-hez. Másképp viselkednek, amikorsh
vagydash
busybox
(mentőlemezeken és hasonlóknál gyakori), akkor nagyjából minden (cp, mv, rm, ls, …) szimbolikus link a busyboxhoz.gcc
,bash
,gunzip
, az operációs rendszer többi részének nagy része …), mivel a Linux csak a kernel.