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
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
ogbzip2
, 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]
ersh
. Det kører som en login-shell, nårargv[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 tilsystemctl
. - og så videre.
Kommentarer
- En anden er
sendmail
ogmail
. 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). Ogtex
,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 , hvorexec
tager henvisninger til etiket 2 og etiket 1, og ved etiket2:
visesetc/init\0
, og ved etiket1:
vises en henvisning til etiket 2 og et afsluttende nul), hvilket grundlæggende er, hvadexecve
gør i dag minusenvp
. -
execv
ogexecl
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 :
- 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.
- 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 | $
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.
sh
er symlink tildash
. De opfører sig anderledes, når de kaldessh
eller somdash
busybox
(almindelig på redningsdiske og sådan), så er stort set alt (cp, mv, rm, ls, …) et symbolsk link til optaget boks.gcc
,bash
,gunzip
, det meste af resten af operativsystemet …), da Linux kun er kernen.