Hvorfor inkluderer argv programnavnet?

Typiske Unix / Linux-programmer accepterer kommandolinieindgange som et argumentantal (int argc) og en argumentvektor (char *argv[]). Det første element i argv er programnavnet – efterfulgt af de faktiske argumenter.

Hvorfor sendes programnavnet til den eksekverbare som et argument? Er der eksempler på programmer, der bruger deres eget navn (måske en slags exec situation)?

Kommentarer

  • som mv og cp?
  • På Debian sh er symlink til dash. De opfører sig anderledes, når de kaldes sh eller som dash
  • @AlexejMagura Hvis du bruger noget som busybox (almindelig på redningsdiske og sådan), så er stort set alt (cp, mv, rm, ls, …) et symbolsk link til optaget boks.
  • Jeg ‘ Jeg finder det virkelig svært at ignorere, så jeg ‘ ll sig det: du mener sandsynligvis ” GNU ” programmer (gcc, bash, gunzip, det meste af resten af operativsystemet …), da Linux kun er kernen.
  • @ wizzwizz4 Hvad ‘ er galt med ” Typiske Unix / Linux-programmer “? Jeg læste det som ” Typiske programmer, der kører på Unix / Linux “. At ‘ er meget bedre end din begrænsning til visse GNU-programmer. Dennis Ritchie brugte bestemt ikke nogen GNU-programmer. BTW Hurd-kernen er et eksempel på et GNU-program, som ikke har en hovedfunktion …

Svar

Til at begynde med skal du bemærke, at argv[0] ikke nødvendigvis er programnavnet. Det er det, der ringer op i argv[0] af execve systemopkald (se f.eks. dette spørgsmål om Stack Overflow ). (Alle andre varianter af exec er ikke systemopkald, men grænseflader til execve.)

Antag f.eks. følgende (ved hjælp af execl):

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

/var/tmp/mybackdoor er hvad der udføres, men argv[0] er indstillet til top, og dette er hvad ps eller ( den virkelige) top vises. Se dette svar på U & L SE for mere om dette.

Indstilling af alle dette til side: Før fremkomsten af smarte filsystemer som /proc var argv[0] den eneste måde for en proces at lære om sit eget navn. Hvad ville det være godt for?

  • Flere programmer tilpasser deres adfærd afhængigt af navnet, som de blev kaldt til (normalt ved symbolske eller hårde links, for eksempel BusyBox “hjælpeprogrammer ; flere eksempler findes i andre svar på dette spørgsmål).
  • Desuden afhænger tjenester, dæmoner og andre programmer, der logger igennem syslog, ofte deres navn til logposter; uden dette ville hændelsessporing være næsten umulig.

Kommentarer

  • Eksempler på sådanne programmer er bunzip2, bzcat og bzip2, for hvilke de første to er symlinks til den tredje.
  • @Ruslan Interessant zcat er ikke et symlink. De ser ud til at undgå ulemperne ved denne teknik ved hjælp af et shell-script i stedet. Men de undlader at udskrive en komplet --help output, fordi nogen, der tilføjede muligheder til gzip, glemte at main tain zcat også.
  • Så længe jeg kan huske, har GNU-kodningsstandarderne afskrækket brugen af argv [0] til at ændre programadfærd ( sektion ” Standarder for grænseflader Generelt ” i den aktuelle version ). gunzip er en historisk undtagelse.
  • busybox er et andet glimrende eksempel. Det kan kaldes med 308 forskellige navne for at påkalde forskellige kommandoer: busybox.net/downloads/BusyBox.html#commands
  • Mange, mange flere programmer indsprøjter også deres argv[0] i deres brug / hjælp output i stedet for at kode deres navn. Nogle fuldt ud, andre bare basisnavnet.

Svar

Masser:

  • Bash kører i POSIX-tilstand , når argv[0] er sh. Det kører som en login-shell, når argv[0] begynder med -.
  • Vim opfører sig forskelligt, når det køres som vi, view, evim, eview, ex, vimdiff osv.
  • Busybox, som allerede nævnt.
  • I systemer med systemd som init er shutdown, reboot osv. symlinks til systemctl .
  • og så videre.

Kommentarer

  • En anden er sendmail og mail. Hver eneste unix MTA leveres med et symlink til disse to kommandoer og er designet til at efterligne den originale ‘ s adfærd, når den kaldes som sådan, hvilket betyder, at ethvert unix-program, der skal sende e-mail, ved nøjagtigt hvordan de kan gøre det.
  • en anden almindelig sag: test og [: når du ringer til den tidligere , det håndterer en fejl, hvis det sidste argument er ]. (på faktisk Debian-stabil er disse kommandoer to forskellige programmer, men tidligere versioner og MacOer bruger stadig det samme program). Og tex, latex og så videre: den binære er den samme, men når man ser hvordan den blev kaldt, vælger den den rigtige konfigurationsfil . init er ens.
  • Relateret, [ betragter det som en fejl, hvis det sidste argument er ikke ].
  • Jeg antager, at dette besvarer det andet spørgsmål, men ikke det første. Jeg tvivler meget på, at en eller anden OS-designer satte sig ned og sagde » Hej, det ville være sejt, hvis jeg havde det samme program, der udførte forskellige ting bare baseret på dets eksekverbare navn. Jeg antager, at jeg ‘ vil inkludere navnet i dets argument array, så. «
  • @Joey Ja, formulering er beregnet til at formidle, at (Q: ” Er der nogen …? ” A: ” Masser: … “)

Svar

Historisk set er argv bare en række markører til kommandolinjens “ord”, så det giver mening at starte med det første “ord”, som tilfældigvis er programmets navn.

Og der er en hel del programmer, der opfører sig forskelligt, i henhold til hvilket navn der bruges til at kalde dem, så du kan bare oprette forskellige links til dem og få forskellige “kommandoer”. mest ekstreme eksempel, jeg kan tænke på, er busybox , som fungerer som flere dusin forskellige “kommandoer” afhængigt af hvordan det hedder .

Rediger

: Referencer til Unix 1. udgave, som ønsket

Man kan se f.eks. fra hoved funktion af cc at argc og argv blev allerede brugt. shell kopierer argumenter til parbuf inde i newarg delen af sløjfen, mens man behandler selve kommandoen på samme måde som argumenterne. (Selvfølgelig udfører det senere kun det første argument, som er navnet på kommandoen). Det ser ud til, at execv og slægtninge ikke eksisterede dengang.

Kommentarer

  • tilføj venligst referencer, der sikkerhedskopier dette.
  • Fra en hurtig skimming tager exec navnet på kommandoen, der skal udføres, og et nultermineret array af charpointer (bedst set ved minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , hvor exec tager henvisninger til etiket 2 og etiket 1, og ved etiket 2: vises etc/init\0, og ved etiket 1: vises en henvisning til etiket 2 og et afsluttende nul), hvilket grundlæggende er, hvad execve gør i dag minus envp.
  • execv og execl har eksisteret ” for evigt ” (dvs. siden begyndelsen til midten af 1970erne) – execv var et systemopkald og var en biblioteksfunktion, der kaldte det. execve eksisterede ikke ‘ da fordi miljøet ikke eksisterede ‘ t da. De øvrige familiemedlemmer blev tilføjet senere.
  • @ G-Man Kan du pege på execv i v1-kilden, jeg linkede? Bare nysgerrig.

Svar

Brug sager:

Du kan bruge programnavnet til at ændre programadfærd .

For eksempel kan du oprette nogle symlinks til den faktiske binære.

Et berømt eksempel, hvor denne teknik bruges, er optagelsesboksprojektet, der kun installerer en enkelt binær og mange symlinks til den. (ls, cp, mv osv.). De gør det for at spare lagerplads fordi deres mål er små indlejrede enheder.

Dette er også brugt i setarch fra 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 

Her bruger de denne teknik grundlæggende for at undgå mange duplikerede kildefiler eller bare for at holde kilderne mere læsbare.

En anden brugssag ville være et program, der har brug for for at indlæse nogle moduler eller data ved kørsel. At have programstien gør dig i stand til at indlæse moduler fra en sti i forhold til programplaceringen .

Desuden udskriver mange programmer fejlmeddelelser inklusive programnavnet .

Hvorfor :

  1. Fordi det er POSIX-konvention ( man 3p execve):

argv er en række argumentstrenge, der sendes til det nye program. Efter konvention skal den første af disse strenge indeholde filnavnet, der er knyttet til den fil, der udføres.

  1. Det er s C standard (mindst C99 og C11):

Hvis værdien af argc er større end nul, strengen peget på af argv [0 ] repræsenterer programnavnet; argv [0] [0] skal være nulltegnet, hvis programnavnet ikke er tilgængeligt fra værtsmiljøet.

Bemærk, at C-standarden siger “program navn “ikke” filnavn “.

Kommentarer

  • Gør ‘ ikke denne pause, hvis du når symlink fra et andet symlink?
  • @Mehrdad, Ja, at ‘ er ulempen og kan være forvirrende for brugeren.
  • @rudimeier: Dine ‘ Hvorfor ‘ emner ikke rigtig er grunde, de ‘ er bare en ” homunculus “, dvs. det spørger bare, hvorfor kræver standarden, at dette er tilfældet.
  • @ einpoklum OP ‘ s spørgsmål var: Hvorfor overføres programnavnet til den eksekverbare? Jeg svarede: Fordi POSIX- og C-standarden fortæller os, at vi skal gøre det. Hvordan synes du, at ‘ ikke er virkelig en grund ? Hvis de dokumenter, jeg ‘ har citeret ikke ville eksistere, ville mange programmer sandsynligvis ikke passere programnavnet.
  • OP beder effektivt ” HVORFOR siger POSIX- og C-standarderne at gøre dette? ” Indrømmet ordlyden var på et abstraheret niveau, men det synes klart. Realistisk set er den eneste måde at vide at spørge ophavsmændene.

Svar

Ud over programmer, der ændrer deres adfærd afhængigt af, hvordan de blev kaldt, finder jeg argv[0] nyttigt til udskrivning af brugen af et program som sådan:

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

Dette får brugsmeddelelsen til altid at bruge det navn, som den blev kaldt igennem. Hvis programmet omdøbes, ændres dets brugsmeddelelse med det. Det inkluderer endda det stienavn, det blev kaldt 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 er en god touch, især til små specialværktøjer / scripts, der muligvis lever overalt stedet.

Dette forekommer også almindelig praksis i GNU-værktøjer, se ls for eksempel:

% 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. Jeg ville foreslå det samme. Underligt at så mange mennesker fokuserer på at ændre adfærd og ikke nævner sandsynligvis det mest oplagte og meget mere udbredt brug.

Svar

Man udfører programtypen: program_name0 arg1 arg2 arg3 ....

Så skal shell allerede dele tokenet, og det første token er allerede programnavnet. Og BTW, så der er de samme indekser på programsiden og på shell.

Jeg synes, det var bare et bekvemmelighedstrick (lige i starten), og som du ser i andre svar, var det også meget praktisk, så denne tradition blev fortsat og s et som API.

Svar

Grundlæggende inkluderer argv programnavnet, så du kan skrive fejlmeddelelser som prgm: file: No such file or directory, som ville blive implementeret med noget som dette:

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

Svar

Et andet eksempel på en anvendelse af dette er dette program, der erstatter sig selv med … sig selv, indtil du skriver noget, der ikke er “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; } 

Naturligvis en slags konstrueret, hvis interessant eksempel, men jeg tror, det kan have reelle anvendelser – for eksempel en selvopdaterende binær, som omskriver sin egen hukommelsesplads med en ny version af sig selv, som den downloadede eller ændrede.

Eksempel:

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

Kilde og lidt mere info .

Kommentarer

  • Tillykke med at nå 1000.

Svar

Stien til programmet er argv[0], så programmet kan hent konfigurationsfiler osv. fra sin installationsmappe.
Dette ville være umuligt uden argv[0].

Kommentarer

  • At ‘ ikke er en særlig god forklaring – der er ‘ ingen grund til, at vi ikke kunne ‘ t er standardiseret på noget som (char *path_to_program, char **argv, int argc) for eksempel
  • Afaik, de fleste programmer henter konfiguration fra en standardplacering (~/.<program>, /etc/<program, $XDG_CONFIG_HOME ) og tag enten en parameter for at ændre det eller have en kompileringstid, der bager konstant i det binære.

Svar

ccache opfører sig sådan for at efterligne forskellige opkald til compiler-binære filer. ccache er en kompilationscache – hele pointen er aldrig at kompilere den samme kildekode to gange, men i stedet returnere objektkoden fra cachen, hvis det er muligt.

Fra ccache man-side , “der er to måder at bruge ccache på. Du kan enten forudse dine kompileringskommandoer med ccache, eller du kan lade ccache maskerere som kompilatoren ved at oprette et symbolsk link (navngivet som compileren) til ccache. den første metode er mest praktisk, hvis du bare vil prøve ccache eller ønsker at bruge den til nogle specifikke projekter. Den anden metode er mest nyttig, når du vil bruge ccache til alle dine kompileringer. “

symlinks-metoden indebærer at køre disse kommandoer:

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

… hvis virkning er at tillade ccache at fange alle kommandoer, som ellers ville være gået til compilerne således at ccache kan returnere en cachelagret fil eller videresende kommandoen til den aktuelle compiler.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *