Typische Unix / Linux-programmas accepteren de invoer van de opdrachtregel als een aantal argumenten (int argc
) en een argumentvector (char *argv[]
). Het eerste element van argv
is de programmanaam – gevolgd door de eigenlijke argumenten.
Waarom wordt de programmanaam als een argument aan het uitvoerbare bestand doorgegeven? Zijn er voorbeelden van programmas die hun eigen naam gebruiken (misschien een soort exec
situatie)?
Opmerkingen
Answer
Merk om te beginnen op dat argv[0]
niet noodzakelijk de naam van het programma is. Het is wat de beller in argv[0]
van de execve
systeemaanroep plaatst (zie bijvoorbeeld deze vraag over Stack Overflow ). (Alle andere varianten van exec
zijn geen systeemaanroepen maar interfaces naar execve
.)
Stel, bijvoorbeeld, het volgende (met execl
):
execl("/var/tmp/mybackdoor", "top", NULL);
/var/tmp/mybackdoor
is wat wordt uitgevoerd maar argv[0]
is ingesteld op top
, en dit is wat ps
of ( de echte) top
zou worden weergegeven. Zie dit antwoord op U & L SE voor meer informatie hierover.
Alles instellen dit terzijde: vóór de komst van fraaie bestandssystemen zoals /proc
, was argv[0]
de enige manier voor een proces om zijn eigen naam te leren. Waar zou dat goed voor zijn?
- Verschillende programmas passen hun gedrag aan afhankelijk van de naam waarmee ze werden aangeroepen (meestal door symbolische of harde links, bijvoorbeeld hulpprogrammas van BusyBox ; er worden nog meer voorbeelden gegeven in andere antwoorden op deze vraag).
- Bovendien plaatsen services, daemons en andere programmas die via syslog inloggen hun naam vaak voor de logboekvermeldingen; zonder dit zou het bijhouden van gebeurtenissen bijna onmogelijk worden.
Reacties
- Voorbeelden van dergelijke programmas zijn
bunzip2
,bzcat
enbzip2
, waarvan de eerste twee symbolische links naar de derde zijn. - @Ruslan Interessant is dat
zcat
geen symlink is. Ze lijken de nadelen van deze techniek te vermijden door in plaats daarvan een shell-script af te drukken. Maar ze slagen er niet in een volledige output omdat iemand die opties aan gzip heeft toegevoegd, vergat om main tain zcat. - Zolang ik me kan herinneren, hebben de GNU-coderingsstandaarden het gebruik van argv [0] om programmagedrag te veranderen ontmoedigd ( sectie ” Standaarden voor interfaces in het algemeen ” in de huidige versie ).
gunzip
is een historische uitzondering. - busybox is een ander uitstekend voorbeeld. Het kan worden aangeroepen door 308 verschillende namen om verschillende commandos aan te roepen: busybox.net/downloads/BusyBox.html#commands
- Veel, veel meer programmas injecteren ook hun
argv[0]
in hun gebruik / help-uitvoer in plaats van hun naam hard te coderen. Sommige volledig, sommige alleen de basisnaam.
Antwoord
Veel:
- Bash wordt uitgevoerd in POSIX-modus wanneer
argv[0]
sh
is. Het draait als een login-shell wanneerargv[0]
begint met-
. - Vim gedraagt zich anders wanneer het wordt uitgevoerd als
vi
,view
,evim
,eview
,ex
,vimdiff
, enz. - Busybox, zoals reeds vermeld.
- In systemen met systemd als init,
shutdown
,reboot
, etc. zijn symlinks naarsystemctl
. - enzovoort.
Reacties
- Een andere is
sendmail
enmail
. Elke unix-MTA wordt geleverd met een symlink voor die twee commandos, en is ontworpen om het oorspronkelijke gedrag van ‘ te emuleren wanneer het als zodanig wordt aangeroepen, wat betekent dat elk Unix-programma dat e-mail moet verzenden weet precies hoe ze dat kunnen doen. - een ander veel voorkomend geval:
test
en[
: wanneer je de eerste aanroept , het behandelt een fout als het laatste argument]
is. (op de werkelijke Debian-stal zijn deze commandos twee verschillende programmas, maar eerdere versies en MacOs gebruiken nog steeds hetzelfde programma). Entex
,latex
enzovoort: het binaire bestand is hetzelfde, maar kijkend hoe het werd genoemd, kiest het de juiste configuratie bestand.init
is vergelijkbaar. - Gerelateerd,
[
beschouwt het als een fout als het laatste argument niet]
. - Ik denk dat dit de tweede vraag beantwoordt, maar niet de eerste. Ik betwijfel ten zeerste of een of andere OS-ontwerper ging zitten en zei » Hé, het zou gaaf zijn als ik hetzelfde programma verschillende dingen zou laten doen alleen op basis van de naam van het uitvoerbare bestand. Ik denk dat ik ‘ de naam zal opnemen in de argumentarray. «
- @Joey Ja, de formulering is bedoeld om over te brengen dat (Q: ” Zijn er …? ” A: ” Veel: … “)
Antwoord
Historisch gezien is argv
slechts een reeks verwijzingen naar de “woorden” van de opdrachtregel, dus is het logisch om te beginnen met het eerste “woord”, dat toevallig het naam van het programma.
En er zijn nogal wat programmas die zich anders gedragen volgens de naam die wordt gebruikt om ze aan te roepen, dus je kunt gewoon verschillende links naar ze maken en verschillende “opdrachten” krijgen. Het meest extreme voorbeeld dat ik kan bedenken is busybox , die zich gedraagt als tientallen verschillende “opdrachten”, afhankelijk van hoe het wordt genoemd .
Bewerken
: Referenties voor Unix 1e editie, zoals gevraagd
Men kan b.v. van de main -functie van cc
die argc
en argv
werden al gebruikt. De shell kopieert argumenten naar de parbuf
binnen het newarg
deel van de lus, terwijl het commando zelf op dezelfde manier wordt behandeld als de argumenten. (Natuurlijk voert het later alleen het eerste argument uit, dat is de naam van het commando). Het lijkt erop dat execv
en familieleden “toen nog niet bestonden.
Reacties
- voeg referenties toe die maak hier een back-up van.
- Van een snelle skimming,
exec
neemt de naam van het uit te voeren commando en een nul-beëindigde reeks tekenaanwijzers (het beste te zien op minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , waarbijexec
neemt verwijzingen naar label 2 en label 1, en op label2:
verschijntetc/init\0
, en op label1:
verschijnt een verwijzing naar label 2, en een afsluitende nul), wat eigenlijk is watexecve
vandaag doet minenvp
. -
execv
enexecl
bestaan ” voor altijd ” (dwz sinds het begin van de jaren 70) –execv
was een systeemaanroep en was een bibliotheekfunctie die het noemde.execve
bestond toen nog niet ‘ omdat de omgeving toen nog niet ‘ bestond. De andere leden van de familie zijn later toegevoegd. - @ G-Man Kun je me verwijzen naar
execv
in de v1-bron die ik heb gelinkt? Gewoon nieuwsgierig.
Antwoord
Gebruiksgevallen:
U kunt de programmanaam gebruiken om het programmagedrag te wijzigen .
U kunt bijvoorbeeld enkele symlinks naar het daadwerkelijke binaire bestand maken.
Een beroemd voorbeeld waarbij deze techniek wordt gebruikt, is het busybox-project dat slechts één enkel binair bestand en vele symlinks ernaar installeert. (ls, cp, mv, enz.). Ze doen het om opslagruimte te besparen omdat hun doelen kleine ingebedde apparaten zijn.
Dit is ook gebruikt in setarch
van util-linux:
$ 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
Hier gebruiken ze deze techniek in principe om veel dubbele bronbestanden te vermijden of gewoon om de bronnen beter leesbaar te houden.
Een ander gebruik is een programma dat om sommige modules of gegevens tijdens runtime te laden. Het hebben van het programmapad stelt je in staat modules te laden vanaf een pad relatief aan de programmalocatie .
Bovendien drukken veel programmas foutmeldingen af, inclusief de programmanaam .
Waarom :
- Omdat het POSIX-conventie is (
man 3p execve
):
argv is een array van argumentstrings die aan het nieuwe programma worden doorgegeven. Volgens afspraak moet de eerste van deze strings de bestandsnaam bevatten die is gekoppeld aan het bestand dat wordt uitgevoerd.
- Het is C standard (minimaal C99 en C11):
Als de waarde van argc groter is dan nul, wordt de string waarnaar wordt verwezen door argv [0 ] staat voor de programmanaam; argv [0] [0] zal het nul-teken zijn als de programmanaam niet beschikbaar is vanuit de hostomgeving.
Merk op dat de C-standaard zegt “programma name “not” filename “.
Reacties
- Doet deze pauze niet ‘ als je de symlink van een andere symlink?
- @Mehrdad, ja dat ‘ is de keerzijde en kan verwarrend zijn voor de gebruiker.
- @rudimeier: Uw ‘ Waarom ‘ items zijn niet echt een reden, ze ‘ zijn slechts een ” homunculus “, dwz het roept de vraag op waarom de standaard vereist dat dit het geval is.
- @ einpoklum OP ‘ s vraag was: Waarom wordt de programmanaam doorgegeven aan het uitvoerbare bestand? Ik antwoordde: Omdat POSIX en C-standaard ons vertellen om dit te doen. Hoe denk je dat ‘ niet echt een reden is? Als de documenten die ik ‘ heb aangehaald niet zouden bestaan, dan zouden veel programmas de programmanaam waarschijnlijk niet doorgeven.
- Het OP vraagt in feite ” WAAROM zeggen de POSIX- en C-standaarden dit te doen? ” Toegegeven, de formulering was op een abstract niveau, maar het lijkt duidelijk. Realistisch gezien is de enige manier om dit te weten, te vragen aan de opstellers.
Answer
Naast programmas die hun gedrag afhankelijk van hoe ze werden genoemd, vind ik argv[0]
nuttig bij het afdrukken van het gebruik van een programma, zoals:
printf("Usage: %s [arguments]\n", argv[0]);
Dit zorgt ervoor dat het gebruiksbericht altijd de naam gebruikt waarmee het werd aangeroepen. Als het programma een andere naam krijgt, verandert het gebruiksbericht mee. Het bevat zelfs de padnaam waarmee het werd aangeroepen:
# 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]
Het is een leuke bijkomstigheid, vooral voor kleine speciale tools / scripts die overal kunnen voorkomen de plaats.
Dit lijkt ook gebruikelijk in GNU-tools, zie ls
bijvoorbeeld:
% 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.
Reacties
- +1. Ik wilde hetzelfde suggereren. Vreemd dat zoveel mensen focussen op gedragsverandering en de waarschijnlijk meest voor de hand liggende en veel meer wijdverbreid gebruik.
Antwoord
Men voert het programma uit door te typen: program_name0 arg1 arg2 arg3 ...
.
Dus de shell zou het token al moeten verdelen, en het eerste token is al de programmanaam. En trouwens, er zijn dus dezelfde indices aan programmazijde en aan shell.
Ik denk dat dit slechts een gemakstruc was (vanaf het allereerste begin), en zoals je in andere antwoorden ziet, was het ook erg handig, dus deze traditie werd voortgezet en et als API.
Answer
In principe bevat argv de programmanaam zodat u foutmeldingen kunt schrijven zoals prgm: file: No such file or directory
, dat zou worden geïmplementeerd met zoiets als dit:
fprintf( stderr, "%s: %s: No such file or directory\n", argv[0], argv[1] );
Antwoord
Een ander voorbeeld van een toepassing hiervan is dit programma, dat zichzelf vervangt door … zichzelf, totdat je iets typt dat niet “t y
is.
#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; }
Uiteraard een soort gekunsteld, maar interessant voorbeeld, maar ik denk dat dit echt nuttig kan zijn – bijvoorbeeld een zichzelf bijwerkend binair bestand, dat herschrijft zijn eigen geheugenruimte met een nieuwe versie van zichzelf die hij heeft gedownload of gewijzigd.
Voorbeeld:
$ ./res 1 arg: 1 y arg: 2 y arg: 3 y arg: 4 y arg: 5 y arg: 6 y arg: 7 n 7 | $
Reacties
- Gefeliciteerd met het bereiken van 1000.
Answer
Het pad naar het programma is argv[0]
, zodat het programma kan haal configuratiebestanden enz. op uit de installatiemap.
Dit zou onmogelijk zijn zonder argv[0]
.
Reacties
- Dat ‘ is geen bijzonder goede uitleg – er is ‘ geen reden waarom we ‘ t hebben gestandaardiseerd op iets als
(char *path_to_program, char **argv, int argc)
bijvoorbeeld - Afaik, de meeste programmas halen de configuratie uit een standaardlocatie (
~/.<program>
,/etc/<program
,$XDG_CONFIG_HOME
) en ofwel een parameter nemen om deze te wijzigen of een compilatietijdoptie hebben die een constante naar het binaire bestand bakt.
Answer
ccache gedraagt zich op deze manier om te imiteren verschillende aanroepen naar binaire bestanden van de compiler. ccache is een compilatiecache – het gaat erom nooit dezelfde broncode twee keer te compileren, maar in plaats daarvan de objectcode indien mogelijk uit de cache te retourneren.
Van de ccache manpage , “zijn er twee manieren om ccache te gebruiken. U kunt uw compilatieopdrachten voorvoegsel met ccache of u kunt ccache zich laten voordoen als de compiler door een symbolische link (genaamd de compiler) naar ccache te maken. De De eerste methode is het handigst als je alleen ccache wilt uitproberen of het voor een aantal specifieke projecten wilt gebruiken. De tweede methode is het handigst als je ccache voor al je compilaties wilt gebruiken. “
De symlinks methode omvat het uitvoeren van deze commandos:
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 ...
… het effect hiervan is dat ccache alle commandos kan haken die anders naar de compilers zouden zijn gegaan, waardoor ccache een in de cache opgeslagen bestand kan retourneren of het commando kan doorgeven aan de daadwerkelijke compiler.
sh
een symlink naardash
. Ze gedragen zich anders, wanneer ze worden aangeroepen alssh
of alsdash
busybox
(gebruikelijk op reddingsschijven en dergelijke), dan is vrijwel alles (cp, mv, rm, ls, …) een symbolische link naar busybox.gcc
,bash
,gunzip
, de meeste van de rest van het besturingssysteem …), aangezien Linux slechts de kernel is.