Varför innehåller argv programnamnet?

Typiska Unix / Linux-program accepterar kommandoradsingångarna som ett argumentantal (int argc) och en argumentvektor (char *argv[]). Det första elementet i argv är programnamnet – följt av de faktiska argumenten.

Varför skickas programnamnet till den körbara filen som ett argument? Finns det några exempel på program som använder sitt eget namn (kanske någon form av exec situation)?

Kommentarer

  • som mv och cp?
  • På Debian sh är symlink till dash. De beter sig annorlunda när de kallas sh eller som dash
  • @AlexejMagura Om du använder något som busybox (vanligt på räddningsskivor och liknande), då är ganska mycket allt (cp, mv, rm, ls, …) en symbolisk länk till upptagenbox.
  • Jag ’ jag tycker att detta verkligen är svårt att ignorera, så jag ’ ll säg det: du menar förmodligen ” GNU ” -program (gcc, bash, gunzip, större delen av resten av operativsystemet …), eftersom Linux bara är kärnan.
  • @ wizzwizz4 Vad ’ är fel med ” Typiska Unix / Linux-program ”? Jag läste det som ” Typiska program som körs på Unix / Linux ”. Att ’ är mycket bättre än din begränsning till vissa GNU-program. Dennis Ritchie använde verkligen inga GNU-program. BTW är Hurd-kärnan ett exempel på ett GNU-program som inte har någon huvudfunktion …

Svar

Till att börja med, notera att argv[0] inte nödvändigtvis är programnamnet. Det är vad den som ringer sätter i argv[0] i execve systemanropet (t.ex. se den här frågan om Stack Overflow ). (Alla andra varianter av exec är inte systemanrop utan gränssnitt till execve.)

Antag till exempel följande (med execl):

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

/var/tmp/mybackdoor är vad som körs men argv[0] är inställt på top, och detta är vad ps eller ( den verkliga) top skulle visas. Se detta svar på U & L SE för mer om detta.

Ställa in alla detta åt sidan: Före tillkomsten av snygga filsystem som /proc var argv[0] det enda sättet för en process att lära sig om sitt eget namn. Vad skulle det vara bra för?

  • Flera program anpassar sitt beteende beroende på namnet de kallades på (vanligtvis med symboliska eller hårda länkar, till exempel BusyBox verktyg ; flera andra exempel ges i andra svar på denna fråga).
  • Dessutom förtjänar tjänster, demoner och andra program som loggar genom syslog ofta sitt namn till loggposter; utan detta skulle händelsespårning bli nästan omöjligt.

Kommentarer

  • Exempel på sådana program är bunzip2, bzcat och bzip2, för vilka de två första är symlänkar till den tredje.
  • @Ruslan Intressant zcat är inte en symlänk. De verkar undvika nackdelarna med denna teknik med ett skalskript istället. Men de kan inte skriva ut en fullständig --help -output eftersom någon som lade till alternativ till gzip glömde att main tain zcat också.
  • Så länge jag kan komma ihåg har GNU-kodningsstandarderna avskräckt från att använda argv [0] för att ändra programbeteende ( avsnitt ” Standarder för gränssnitt Generellt ” i den aktuella versionen ). gunzip är ett historiskt undantag.
  • upptagen låda är ett annat utmärkt exempel. Det kan kallas med 308 olika namn för att anropa olika kommandon: busybox.net/downloads/BusyBox.html#commands
  • Många, många fler program injicerar också deras argv[0] i deras användnings- / hjälputdata istället för att hårdkoda namnet. Vissa i sin helhet, andra bara basnamnet.

Svar

Gott:

  • Bash körs i POSIX-läge när argv[0] är sh. Det körs som ett inloggningsskal när argv[0] börjar med -.
  • Vim beter sig annorlunda när den körs som vi, view, evim, eview, ex, vimdiff osv.
  • Busybox, som redan nämnts.
  • I system med systemd som init är shutdown, reboot etc. symlänkar till systemctl .
  • och så vidare.

Kommentarer

  • En annan är sendmail och mail. Varje unix MTA kommer med en symlink för dessa två kommandon och är utformad för att emulera det ursprungliga ’ beteendet när det kallas som sådant, vilket betyder att alla unix-program som behöver skicka e-post vet exakt hur de kan göra det.
  • ett annat vanligt fall: test och [: när du ringer till den förra , det hanterar ett fel om det sista argumentet är ]. (på Debian-stabil är dessa kommandon två olika program, men tidigare versioner och MacO använder fortfarande samma program). Och tex, latex och så vidare: binären är densamma, men ser hur den hette, väljer den rätt konfigurationsfil . init liknar.
  • Relaterat, [ anser att det är ett fel om det sista argumentet är inte ].
  • Jag antar att det besvarar den andra frågan, men inte den första. Jag tvivlar mycket på att någon OS-designer satte sig ner och sa » Hej, det skulle vara kul om jag hade samma program som gjorde olika saker bara baserat på dess körbara namn. Jag antar att jag ’ kommer att inkludera namnet i dess argumentmatris, då. «
  • @Joey Ja, formuleringen är avsedd att förmedla att (Q: ” Finns det någon …? ” A: ” Gott: … ”)

Svar

Historiskt är argv bara en rad pekare till ”ord” i kommandoraden, så det är vettigt att börja med det första ”ordet”, som råkar vara programmets namn.

Och det finns en hel del program som beter sig olika enligt vilket namn som används för att kalla dem, så du kan bara skapa olika länkar till dem och få olika ”kommandon”. mest extrema exempel jag kan tänka mig är upptagen låda , som fungerar som flera dussin olika ”kommandon” beroende på hur det heter .

Redigera

: Referenser för Unix 1: a upplagan, enligt begäran

Man kan se t.ex. från huvud -funktionen för cc att argc och argv användes redan. skalet kopierar argument till parbuf inuti newarg delen av slingan, samtidigt som kommandot behandlas på samma sätt som argumenten. (Självklart kör det senare bara det första argumentet, vilket är kommandot). Det ser ut som att execv och släktingar inte fanns då.

Kommentarer

  • lägg till referenser som säkerhetskopiera detta.
  • Från ett snabbt skumning tar exec namnet på kommandot som ska köras och en nollavslutad uppsättning char-pekare (ses bäst vid minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , där exec tar referenser till etikett 2 och etikett 1 och vid etikett 2: visas etc/init\0 och vid etikett 1: visas en hänvisning till etikett 2 och en avslutande noll), vilket i princip är vad execve gör idag minus envp.
  • execv och execl har funnits ” för alltid ” (dvs. sedan början till mitten av 1970-talet) – execv var ett systemanrop och var en biblioteksfunktion som kallade den. execve existerade inte ’ eftersom miljön inte fanns ’ t då. De andra familjemedlemmarna lades till senare.
  • @ G-Man Kan du rikta mig till execv i v1-källan som jag länkade? Bara nyfiken.

Svar

Användningsfall:

Du kan använda programnamnet för att ändra programbeteendet .

Du kan till exempel skapa några symlänkar till den faktiska binära.

Ett känt exempel där denna teknik används är upptagenboxprojektet som bara installerar en enda binär och många symlänkar till den. (ls, cp, mv, etc). De gör det för att spara lagringsutrymme eftersom deras mål är små inbäddade enheter.

Detta är också används i setarch från 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 

Här använder de denna teknik i princip för att undvika många dubbla källfiler eller bara för att hålla källorna mer läsbara.

Ett annat användningsfall skulle vara ett program som behöver för att ladda vissa moduler eller data vid körning. Med programvägen kan du ladda moduler från en sökväg i förhållande till programplatsen .

Dessutom skriver många program felmeddelanden inklusive programnamnet .

Varför :

  1. Eftersom det är POSIX-konvention ( man 3p execve):

argv är en rad argumentsträngar som skickas till det nya programmet. Enligt konvention bör den första av dessa strängar innehålla filnamnet som är associerat med filen som körs.

  1. Det är C standard (minst C99 och C11):

Om värdet på argc är större än noll, strängen pekad på av argv [0 ] representerar programnamnet; argv [0] [0] ska vara noll tecken om programnamnet inte är tillgängligt från värdmiljön.

Observera att C-standarden säger ”program namn ”inte” filnamn ”.

Kommentarer

  • Inte ’ t denna paus om du når symlink från en annan symlink?
  • @Mehrdad, Ja att ’ är nackdelen och kan vara förvirrande för användaren.
  • @rudimeier: Dina ’ Varför ’ är inte riktigt skäl, de ’ är bara en ” homunculus ”, det vill säga det frågar bara varför kräver standarden att detta ska vara fallet.
  • @ einpoklum OP ’: s fråga var: Varför skickas programnamnet till den körbara? Jag svarade: Eftersom POSIX och C-standarden säger att vi ska göra det. Hur tycker du att ’ inte är verkligen en anledning ? Om de dokument som jag ’ har citerat inte skulle existera skulle många program förmodligen inte klara programnamnet.
  • OP: n frågar faktiskt ” VARFÖR säger POSIX- och C-standarderna att göra detta? ” Beviljas att formuleringen var på en abstraherad nivå, men det verkar tydligt. Realistiskt är det enda sättet att veta att fråga upphovsmännen.

Svar

Förutom program som ändrar deras beteende beroende på hur de hette, jag tycker att argv[0] är användbart för att skriva ut användningen av ett program, som så:

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

Detta gör att användningsmeddelandet alltid använder det namn som det kallades för. Om programmet byts namn ändras dess användningsmeddelande med det. Det innehåller till och med sökvägen som den hette med:

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

Det är en fin touch, speciellt för små specialverktyg / skript som kan leva överallt platsen.

Detta verkar också vara vanligt i GNU-verktyg, se ls till exempel:

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

Kommentarer

  • +1. Jag tänkte föreslå detsamma. Konstigt att så många människor fokuserar på att ändra beteende och inte nämner förmodligen det mest uppenbara och mycket mer utbredd användning.

Svar

Man kör programtypen: program_name0 arg1 arg2 arg3 ....

Så skalet ska redan dela token, och den första token är redan programnamnet. Och BTW så det finns samma index på programsidan och på skalet.

Jag tror att det här bara var ett bekvämlighetstrick (i början), och som du ser i andra svar var det också väldigt praktiskt, så denna tradition fortsatte och et som API.

Svar

I grund och botten innehåller argv programnamnet så att du kan skriva felmeddelanden som prgm: file: No such file or directory, som skulle implementeras med något så här:

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

Svar

Ett annat exempel på en tillämpning av detta är detta program, som ersätter sig själv med … själv tills du skriver något som inte är ”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; } 

Självklart är det ett slags konstruerat om intressant exempel, men jag tror att det kan ha verkliga användningsområden – till exempel en självuppdaterande binär, som skriver om sitt eget minnesutrymme med en ny version av sig själv som den laddade ner eller ändrade.

Exempel:

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

Källa och lite mer info .

Kommentarer

  • Grattis till att du når 1000.

Svar

Sökvägen till programmet är argv[0], så att programmet kan hämta konfigurationsfiler etc. från dess installationskatalog.
Detta skulle vara omöjligt utan argv[0].

Kommentarer

  • Att ’ inte är en särskilt bra förklaring – det finns ’ ingen anledning att vi inte kunde ’ t har standardiserats på något som (char *path_to_program, char **argv, int argc) till exempel
  • Afaik, de flesta program hämtar konfiguration från en standardplats (~/.<program>, /etc/<program, $XDG_CONFIG_HOME ) och antingen ta en parameter för att ändra den eller ha en kompileringstid som bakar i en konstant till den binära.

Svar

ccache beter sig på detta sätt för att imitera olika samtal till kompilatorbinarier. ccache är en kompileringscache – hela poängen är att aldrig kompilera samma källkod två gånger utan istället returnera objektkoden från cache om möjligt.

Från ccache man-sida , ”det finns två sätt att använda ccache. Du kan antingen prefixa dina kompileringskommandon med ccache eller så kan du låta ccache maskerera som kompilatorn genom att skapa en symbolisk länk (namngiven som kompilatorn) till ccache. den första metoden är mest praktisk om du bara vill prova ccache eller använda den för vissa specifika projekt. Den andra metoden är mest användbar när du vill använda ccache för alla dina sammanställningar. ”

symlinks-metoden innebär att du kör dessa kommandon:

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

… vars effekt är att ccache låter alla kommandon som annars skulle ha gått till kompilatorerna, vilket gör att ccache kan returnera en cachad fil eller skicka kommandot till själva kompilatorn.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *