Hvorfor inkluderer argv programnavnet? (Norsk)

Typiske Unix / Linux-programmer godtar kommandolinjeinngangene som et argumentantall (int argc) og en argumentvektor (char *argv[]). Det første elementet i argv er programnavnet – etterfulgt av de faktiske argumentene.

Hvorfor blir programnavnet overført til den kjørbare filen som et argument? Er det noen eksempler på programmer som bruker sitt eget navn (kanskje en slags exec situasjon)?

Kommentarer

  • som mv og cp?
  • På Debian sh er symlink til dash. De oppfører seg annerledes når de kalles sh eller som dash
  • @AlexejMagura Hvis du bruker noe som busybox (vanlig på redningsskiver og sånn), så er ganske mye alt (cp, mv, rm, ls, …) en symbolsk lenke til opptattboks.
  • Jeg ‘ Jeg finner dette virkelig vanskelig å ignorere, så jeg ‘ ll si det: du mener sannsynligvis » GNU » programmer (gcc, bash, gunzip, det meste av resten av operativsystemet …), ettersom Linux bare er kjernen.
  • @ wizzwizz4 Hva ‘ er galt med » Typiske Unix / Linux-programmer «? Jeg leste det som » Typiske programmer som kjører på Unix / Linux «. At ‘ er mye bedre enn din begrensning til visse GNU-programmer. Dennis Ritchie brukte absolutt ingen GNU-programmer. BTW Hurd-kjernen er et eksempel på et GNU-program som ikke har noen hovedfunksjon …

Svar

Til å begynne med, vær oppmerksom på at argv[0] ikke nødvendigvis er programnavnet. Det er det innringeren legger i argv[0] av execve systemanropet (f.eks. Se dette spørsmålet om Stack Overflow ). (Alle andre varianter av exec er ikke systemanrop, men grensesnitt til execve.)

Anta for eksempel følgende (ved hjelp av execl):

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

/var/tmp/mybackdoor er det som kjøres men argv[0] er satt til top, og dette er hva ps eller ( den virkelige) top vil vises. Se dette svaret på U & L SE for mer om dette.

Innstilling av alle dette til side: Før advent av fancy filsystemer som /proc, var argv[0] den eneste måten en prosess kunne lære om sitt eget navn. Hva ville det være bra for?

  • Flere programmer tilpasser deres oppførsel avhengig av navnet de ble kalt til (vanligvis ved symbolske eller harde lenker, for eksempel BusyBox «verktøy ; flere eksempler er gitt i andre svar på dette spørsmålet).
  • Dessuten avhenger tjenester, demoner og andre programmer som logger gjennom syslog ofte navnet sitt til loggoppføringer; uten dette vil hendelsessporing være nærmest umulig.

Kommentarer

  • Eksempler på slike programmer er bunzip2, bzcat og bzip2, for hvilke de to første er symlenker til den tredje.
  • @Ruslan Interessant zcat er ikke en symlink. De ser ut til å unngå ulemper ved denne teknikken ved å bruke et skallskript i stedet. Men de klarer ikke å skrive ut en fullstendig --help utgang fordi noen som la til alternativer til gzip glemte å hovedkode tain zcat også.
  • Så lenge jeg kan huske, har GNU-kodingsstandardene motvirket bruken av argv [0] for å endre programadferd ( seksjon » Standarder for grensesnitt Generelt » i gjeldende versjon ). gunzip er et historisk unntak.
  • busybox er et annet utmerket eksempel. Det kan kalles med 308 forskjellige navn for å påkalle forskjellige kommandoer: busybox.net/downloads/BusyBox.html#commands
  • Mange, mange flere programmer injiserer også argv[0] i bruken / hjelpen i stedet for å hardkode navnet. Noen i sin helhet, noen bare basenavnet.

Svar

Rikelig:

  • Bash kjører i POSIX-modus når argv[0] er sh. Den kjører som et påloggingsskall når argv[0] begynner med -.
  • Vim oppfører seg annerledes når den kjøres som vi, view, evim, eview, ex, vimdiff osv.
  • Busybox, som allerede nevnt.
  • I systemer med systemd som init er shutdown, reboot osv. symlenker til systemctl .
  • og så videre.

Kommentarer

  • En annen er sendmail og mail. Hver eneste unix MTA leveres med en symlink for de to kommandoene, og er designet for å etterligne den opprinnelige ‘ oppførselen når den kalles slik, noe som betyr at ethvert unix-program som trenger å sende e-post nøyaktig hvordan de kan gjøre det.
  • et annet vanlig tilfelle: test og [: når du ringer den tidligere , den håndterer en feil hvis det siste argumentet er ]. (på faktisk Debian-stabil er disse kommandoene to forskjellige programmer, men tidligere versjoner og MacO-er bruker fortsatt det samme programmet). Og tex, latex og så videre: den binære er den samme, men ser hvordan den ble kalt, valgte den riktig konfigurasjonsfil . init er lik.
  • Relatert, [ anser det som en feil hvis det siste argumentet er ikke ].
  • Jeg antar at dette svarer på det andre spørsmålet, men ikke det første. Jeg tviler veldig på at noen OS-designere satte seg ned og sa » Hei, det ville vært kult hvis jeg hadde det samme programmet som gjorde forskjellige ting bare basert på det kjørbare navnet. Jeg antar at jeg ‘ vil inkludere navnet i argumentmatrisen, da. «
  • @Joey Ja, formulering er ment å formidle at (Q: » Er det noen …? » A: » Rikelig: … «)

Svar

Historisk sett er argv bare en rekke pekere til «ordene» i kommandolinjen, så det er fornuftig å starte med det første «ordet», som tilfeldigvis er navnet på programmet.

Og det er ganske mange programmer som oppfører seg annerledes i henhold til hvilket navn som brukes til å kalle dem, så du kan bare opprette forskjellige lenker til dem og få forskjellige «kommandoer». mest ekstreme eksempelet jeg kan tenke meg er busybox , som fungerer som flere dusin forskjellige «kommandoer» avhengig av hvordan det heter .

Rediger

: Referanser for Unix 1. utgave, etter forespørsel

Man kan se f.eks. fra hoved -funksjonen til cc at argc og argv ble allerede brukt. skallet kopierer argumenter til parbuf inne i newarg delen av løkken, mens du behandler selve kommandoen på samme måte som argumentene. (Selvfølgelig, senere utfører den bare det første argumentet, som er navnet på kommandoen). Det ser ut til at execv og slektninger ikke eksisterte da.

Kommentarer

  • vennligst legg til referanser som sikkerhetskopier dette.
  • Fra en rask skimming tar exec navnet på kommandoen som skal utføres, og et null-avsluttet utvalg av char-pekere (ses best på minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , der exec tar referanser til etikett 2 og etikett 1, og ved etikett 2: vises etc/init\0, og ved etikett 1: vises en referanse til etikett 2, og en terminering av null), som i utgangspunktet er hva execve gjør i dag minus envp.
  • execv og execl har eksistert » for alltid » (dvs. siden tidlig til midten av 1970-tallet) – execv var et systemanrop og var en biblioteksfunksjon som kalte det. execve fantes ikke ‘ t da miljøet ikke eksisterte ‘ t da. De andre medlemmene av familien ble lagt til senere.
  • @ G-Man Kan du peke meg på execv i v1-kilden jeg koblet? Bare nysgjerrig.

Svar

Use cases:

Du kan bruke programnavnet for å endre programatferden .

For eksempel kan du opprette noen symlinker til den faktiske binæren.

Et kjent eksempel der denne teknikken brukes, er opptattboks-prosjektet som bare installerer en enkelt binær og mange symlinker til den. (ls, cp, mv, etc). De gjør det for å spare lagringsplass fordi målene deres er små innebygde enheter.

Dette er også brukt 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 bruker de denne teknikken i utgangspunktet for å unngå mange dupliserte kildefiler eller bare for å holde kildene mer lesbare.

En annen brukssak vil være et program som trenger for å laste inn noen moduler eller data ved kjøretid. Å ha programstien gjør at du kan laste moduler fra en bane i forhold til programplasseringen .

Dessuten skriver mange programmer ut feilmeldinger inkludert programnavnet .

Hvorfor :

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

argv er en rekke argumentstrenger sendt til det nye programmet. Etter konvensjon, bør den første av disse strengene inneholde filnavnet som er knyttet til filen som kjøres.

  1. It «s C standard (minst C99 og C11):

Hvis verdien av argc er større enn null, blir strengen pekt på av argv [0 ] representerer programnavnet; argv [0] [0] skal være nulltegnet hvis programnavnet ikke er tilgjengelig fra vertsmiljøet.

Legg merke til at C-standarden sier «program navn «ikke» filnavn «.

Kommentarer

  • Gjør ikke ‘ t denne pausen hvis du når symlink fra en annen symlink?
  • @Mehrdad, Ja at ‘ er ulempen og kan være forvirrende for brukeren.
  • @rudimeier: ‘ Hvorfor ‘ -artikler ikke egentlig er grunner, de ‘ er bare en » homunculus «, dvs. det ber bare spørsmålet om hvorfor krever standarden at dette skal være tilfelle.
  • @ einpoklum OP ‘ spørsmål var: Hvorfor blir programnavnet overført til den kjørbare? Jeg svarte: Fordi POSIX og C-standarden forteller oss å gjøre det. Hvordan tror du at ‘ ikke er virkelig en grunn ? Hvis dokumentene jeg ‘ har sitert ikke ville eksistere, ville sannsynligvis mange programmer ikke passere programnavnet.
  • OPEN spør effektivt » HVORFOR sier POSIX- og C-standardene å gjøre dette? » Gitt at ordlyden var på et abstrakt nivå, men det virker klart. Realistisk sett er den eneste måten å vite å spørre opphavsmennene.

Svar

I tillegg til at programmene endrer deres oppførsel avhengig av hvordan de ble kalt, jeg finner argv[0] nyttig for å skrive ut bruken av et program, slik:

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

Dette fører til at bruksmeldingen alltid bruker navnet den ble kalt gjennom. Hvis programmet blir omdøpt, endres bruksmeldingen med det. Det inkluderer til og med stienavnet det ble kalt 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 fin touch, spesielt for små spesialverktøy / skript som kan leve overalt stedet.

Dette virker også vanlig i GNU-verktøy, 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 skulle foreslå det samme. Merkelig at så mange mennesker fokuserer på å endre atferd og ikke nevner det mest åpenbare og mye mer utbredt bruk.

Svar

Man utfører programtastingen: program_name0 arg1 arg2 arg3 ....

Så skallet skal allerede dele tokenet, og det første tokenet er allerede programnavnet. Og BTW så det er de samme indeksene på programsiden og på skallet.

Jeg tror dette bare var et praktisk triks (helt i begynnelsen), og som du ser i andre svar, var det også veldig nyttig, så denne tradisjonen ble videreført og et som API.

Svar

I utgangspunktet inkluderer argv programnavnet slik at du kan skrive feilmeldinger som prgm: file: No such file or directory, som vil bli implementert med noe sånt som dette:

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

Svar

Et annet eksempel på en applikasjon av dette er dette programmet, som erstatter seg selv med … seg selv, til du skriver inn noe som 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; } 

Tydeligvis en slags konstruert hvis interessant eksempel, men jeg tror dette kan ha reelle bruksområder – for eksempel en selvoppdaterende binær, som omskriver sitt eget minne med en ny versjon av seg selv som den lastet ned eller endret.

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 litt mer info .

Kommentarer

  • Gratulerer med å ha nådd 1000.

Svar

Banen til programmet er argv[0], slik at programmet kan hente konfigurasjonsfiler osv. fra installasjonskatalogen.
Dette ville være umulig uten argv[0].

Kommentarer

  • At ‘ ikke er en særlig god forklaring – det er ‘ ingen grunn til at vi ikke kunne ‘ t har standardisert seg på noe som (char *path_to_program, char **argv, int argc) for eksempel
  • Afaik, de fleste programmer henter konfigurasjon fra et standardsted (~/.<program>, /etc/<program, $XDG_CONFIG_HOME ) og ta enten en parameter for å endre den eller ha et kompileringstid som baker i konstant til binær.

Svar

ccache oppfører seg slik for å etterligne forskjellige samtaler til kompilatorbinarier. ccache er en kompileringsbuffer – hele poenget er aldri å kompilere den samme kildekoden to ganger, men i stedet returnere objektkoden fra cachen hvis mulig.

Fra ccache man-siden , «det er to måter å bruke ccache på. Du kan enten prefiks kompileringskommandoer med ccache, eller du kan la ccache maskerere som kompilatoren ved å opprette en symbolsk lenke (kalt kompilatoren) til ccache. den første metoden er mest praktisk hvis du bare vil prøve ccache eller ønsker å bruke den til noen spesifikke prosjekter. Den andre metoden er mest nyttig når du vil bruke ccache til alle kompileringene dine. «

The symlinks-metoden innebærer å kjøre disse kommandoene:

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

… effekten som er å tillate ccache å fange kommandoer som ellers ville ha gått til kompilatorene, slik at ccache kan returnere en hurtigbufret fil eller sende kommandoen videre til selve kompilatoren.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *