Typické programy Unix / Linux přijímají vstupy příkazového řádku jako počet argumentů (int argc
) a vektor argumentů (char *argv[]
). Prvním prvkem argv
je název programu – následovaný skutečnými argumenty.
Proč je název programu předán spustitelnému souboru jako argument? Existují nějaké příklady programů, které používají vlastní název (možná nějaká exec
situace)?
Komentáře
Odpověď
Nejprve si všimněte, že argv[0]
nemusí být nutně název programu. To je to, co volající vloží do argv[0]
execve
systémového volání (např. Viz tato otázka o přetečení zásobníku ). (Všechny ostatní varianty exec
nejsou systémová volání, ale rozhraní k execve
.)
Předpokládejme například, následující (pomocí execl
):
execl("/var/tmp/mybackdoor", "top", NULL);
/var/tmp/mybackdoor
je co se provede, ale argv[0]
je nastaveno na top
, a to je ps
nebo ( skutečné) top
by se zobrazilo. Další informace najdete v této odpovědi na U & L SE.
Nastavení všech toto stranou: Před příchodem efektních souborových systémů jako /proc
byl argv[0]
jediný způsob, jak se proces mohl dozvědět o svém vlastním jménu. K čemu by to bylo dobré?
- Několik programů přizpůsobuje své chování v závislosti na jménu, kterým byly nazývány (obvykle pomocí symbolických nebo pevných odkazů, například Nástroje BusyBoxu ; v dalších odpovědích na tuto otázku je uvedeno několik dalších příkladů).
- Kromě toho služby, démoni a další programy, které se přihlašují přes syslog, často uvádějí své jméno před protokolovat položky; bez toho by se sledování událostí stalo neproveditelným.
Komentáře
- Příklady takových programů jsou
bunzip2
,bzcat
abzip2
, pro které jsou první dva symbolické odkazy na třetí. - @Ruslan Zajímavé je, že
zcat
není symbolický odkaz. Zdá se, že se vyhýbají negativním stránkám této techniky pomocí skriptu prostředí. Ale nedokáží vytisknout úplnou--help
výstup, protože někdo, kdo přidal možnosti do gzip, zapomněl hlavní tain zcat taky. - Dokud si pamatuji, GNU kódovací standardy odradily použití argv [0] ke změně chování programu (sekce “ Standardy pro rozhraní Obecně “ v aktuální verzi ).
gunzip
je historická výjimka. - busybox je dalším vynikajícím příkladem. Lze jej vyvolat 308 různými jmény pro vyvolání různých příkazů: busybox.net/downloads/BusyBox.html#commands
- Mnoho, mnoho více programů také vloží svůj
argv[0]
do výstupu použití / nápovědy namísto pevného kódování svého jména. Některé celé, jiné pouze základní jméno.
Odpověď
Spousta:
- Bash běží v režimu POSIX , když
argv[0]
jesh
. Funguje jako přihlašovací shell, kdyžargv[0]
začíná-
. - Vim se chová jinak, když je spuštěn jako
vi
,view
,evim
,eview
,ex
,vimdiff
atd. - Busybox, jak již bylo zmíněno.
- V systémech s systemd jako init jsou
shutdown
,reboot
atd. div id = „5d4a64da13“>
symbolické odkazy nasystemctl
.
Komentáře
- Další je
sendmail
amail
. Každá jednotlivá unixová MTA je opatřena symbolickým odkazem na tyto dva příkazy a je navržena tak, aby napodobovala původní chování ‚, když je volána jako taková, což znamená, že jakýkoli unixový program, který potřebuje odesílat poštu, ví jak přesně to mohou udělat. - další běžný případ:
test
a[
: když zavoláte prvnímu , zpracovává chybu, pokud je poslední argument]
. (ve skutečné stabilní verzi Debianu jsou tyto příkazy dva různé programy, ale předchozí verze a MacO stále používají stejný program). Atex
,latex
atd.: Binární soubor je stejný, ale při pohledu na to, jak byl nazýván, zvolí správný konfigurační soubor.init
je podobný. - Související,
[
považuje za chybu, pokud poslední argument není]
. - Myslím, že to odpovídá na druhou otázku, ale ne na první. Velmi pochybuji, že se nějaký designér OS posadil a řekl » Hej, bylo by skvělé, kdybych stejný program dělal různé věci jen na základě jeho spustitelného názvu. Myslím, že tedy ‚ ll vložím jméno do svého pole argumentů. «
- @Joey Ano, formulace má naznačit, že (Q: “ Existují nějaké …? “ A: “ Spousta: … „)
Odpověď
Historicky je argv
jen řada ukazatelů na „slova“ na příkazovém řádku, takže má smysl začít s prvním „slovem“, které je shodou okolností název programu.
Existuje několik programů, které se chovají odlišně podle toho, jaké jméno se používá k jejich volání, takže k nim můžete jednoduše vytvořit různé odkazy a získat různé „příkazy“. nejextrémnější příklad, který mě napadá, je busybox , který funguje jako několik desítek různých „příkazů“ podle toho, jak jmenuje se .
Upravit
: Odkazy pro Unix 1. vydání, jak je požadováno
Lze vidět např. z hlavní funkce cc
, která argc
a argv
již byly použity. prostředí kopíruje argumenty do parbuf
uvnitř newarg
části smyčky, přičemž se samotným příkazem zachází stejně jako s argumenty. (Samozřejmě, později provede pouze první argument, kterým je název příkazu). Vypadá to, že execv
a příbuzní tehdy neexistovali.
Komentáře
- přidejte odkazy, které zazálohujte to.
- Z rychlého prohledávání převezme
exec
název příkazu, který má být proveden, a pole znaků s nulovým zakončením (nejlépe na minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , kdeexec
bere odkazy na štítek 2 a štítek 1 a na štítku2:
se objevíetc/init\0
a na štítku1:
se objeví odkaz na štítek 2 a koncová nula), což je v podstatě to, coexecve
dnes dělá minusenvp
. -
execv
aexecl
existují “ navždy “ (tj. od počátku do poloviny 70. let) –execv
bylo systémové volání a byla funkce knihovny, která to nazvala.execve
tehdy neexistovalo ‚ protože prostředí ‚ tehdy neexistovalo. Ostatní členové rodiny byli přidáni později. - @ G-Man Můžete mi ukázat na
execv
ve zdroji v1, na který jsem odkazoval? Jen jsem zvědavý.
Odpověď
Případy použití:
Můžete změnit název programu .
Můžete například vytvořit několik symbolických odkazů na skutečný binární soubor.
Jedním slavným příkladem, kde se tato technika používá, je projekt busybox, který nainstaluje pouze jeden jediný binární soubor a mnoho symbolických odkazů na něj. (ls, cp, mv atd.). Dělají to , aby ušetřili úložný prostor , protože jejich cílem jsou malá integrovaná zařízení.
Toto je také použitý v setarch
z 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
Zde tuto techniku používají v podstatě vyhnout se mnoha duplicitním zdrojovým souborům nebo jen zajistit lepší čitelnost zdrojů.
Dalším případem použití by byl program, který potřebuje načíst některé moduly nebo data za běhu. Díky programové cestě můžete načíst moduly z cesty relativně k umístění programu .
Mnoho programů tiskne chybové zprávy včetně názvu programu .
Proč :
- Protože jde o konvenci POSIX (
man 3p execve
):
argv je řada řetězců argumentů předaných novému programu. Podle konvence by první z těchto řetězců měl obsahovat název souboru přidružený k prováděnému souboru.
- Je to C standard (alespoň C99 a C11):
Pokud je hodnota argc větší než nula, na řetězec, na který ukazuje argv [0 ] představuje název programu; argv [0] [0] bude nulový znak, pokud název programu není k dispozici z hostitelského prostředí.
Všimněte si, že program C Standard říká „program“ name „not“ název souboru „.
Komentáře
- Neznamená to ‚ tento konec, pokud dosáhnete symbolický odkaz z jiného symbolického odkazu?
- @Mehrdad, Ano, ‚ je nevýhodou a může být pro uživatele matoucí.
- @rudimeier: Vaše ‚ proč ‚ nejsou opravdu důvody, jsou ‚ pouze “ homunculus „, tzn. jen si klade otázku, proč to standard vyžaduje.
- @ Otázka einpoklum OP ‚ byla: Proč je název programu předán spustitelnému souboru? Odpověděl jsem: Protože nám to říká POSIX a C standard. Jak si myslíte, že ‚ to není opravdu důvod ? Pokud by dokumenty, které jsem ‚ citoval, neexistovaly, pak by pravděpodobně mnoho programů neprošlo názvem programu.
- OP se skutečně ptá “ PROČ to říkají standardy POSIX a C? “ Je pravda, že formulace byla na abstrahované úrovni, ale zdá se být jasná. Jediným způsobem, jak to poznat, je zeptat se původců.
Odpovědět
Kromě toho, že programy mění jejich chování v závislosti na tom, jak se jim říká, považuji argv[0]
za užitečné při tisku využití programu, například:
printf("Usage: %s [arguments]\n", argv[0]);
To způsobí, že se ve zprávě o použití vždy použije název, přes který byla volána. Pokud je program přejmenován, změní se s ním i jeho zpráva o použití. Zahrnuje dokonce i cestu, pod kterou byla volána:
# 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]
Je to příjemný dotek, zejména pro malé speciální nástroje / skripty, které mohou žít všude místo.
To se zdá být běžnou praxí i v GNU nástrojích, viz například ls
:
% 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.
Komentáře
- +1. Chystal jsem se navrhnout totéž. Zvláštní, že tolik lidí se zaměřuje na změnu chování a nezmiňuje pravděpodobně nejzřejmější a mnohem rozšířenější využití.
Odpověď
Jeden provede program zadáním: program_name0 arg1 arg2 arg3 ...
.
Takže shell by už měl token rozdělit a první token je již název programu. A BTW, takže na straně programu i na shellu existují stejné indexy.
Myslím, že to byl jen pohodlný trik (na samém začátku), a jak vidíte v dalších odpovědích, byl také velmi užitečný, takže tato tradice pokračovala a s et jako API.
Odpověď
Argv v zásadě obsahuje název programu, takže můžete psát chybové zprávy jako prgm: file: No such file or directory
, který by byl implementován s něčím podobným:
fprintf( stderr, "%s: %s: No such file or directory\n", argv[0], argv[1] );
Odpovědět
Dalším příkladem aplikace tohoto programu je tento program, který se nahrazuje … samotným, dokud nezadáte něco, co není „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; }
Je zřejmé, že jde o vymyšlený, i když zajímavý příklad, ale myslím, že to může mít skutečné využití – například samo-aktualizující se binární soubor, který přepíše vlastní paměťový prostor s novou verzí, kterou stáhl nebo změnil.
Příklad:
$ ./res 1 arg: 1 y arg: 2 y arg: 3 y arg: 4 y arg: 5 y arg: 6 y arg: 7 n 7 | $
Komentáře
- Gratulujeme k dosažení 1 000.
Odpověď
Cesta k programu je argv[0]
, aby program mohl načíst konfigurační soubory atd. ze svého instalačního adresáře.
To by nebylo možné bez argv[0]
.
Komentáře
- To ‚ není nijak zvlášť dobré vysvětlení – ‚ tedy není důvod, proč bychom nemohli ‚ například standardizovali něco jako
(char *path_to_program, char **argv, int argc)
- Afaik, většina programů stahuje konfiguraci ze standardního umístění (
~/.<program>
,/etc/<program
,$XDG_CONFIG_HOME
) a buď změňte parametr, nebo proveďte kompilaci, která se v binární podobě konstantní.
Odpověď
ccache se chová tímto způsobem, aby napodobil různá volání binárních souborů kompilátoru. ccache je kompilační mezipaměť – hlavním bodem nikdy není kompilace stejného zdrojového kódu dvakrát, ale pokud je to možné, vrátí kód objektu z mezipaměti.
Z stránka ccache man , „existují dva způsoby, jak použít ccache. Můžete buď předponu svých kompilačních příkazů zadat ccache, nebo můžete nechat ccache maškarádu jako kompilátor vytvořením symbolického odkazu (pojmenovaného jako kompilátor) na ccache. první metoda je nejvhodnější, pokud si chcete jen vyzkoušet ccache nebo ji chcete použít pro některé konkrétní projekty. Druhá metoda je nejužitečnější, pokud chcete použít ccache pro všechny své kompilace. „
The Metoda symbolických odkazů zahrnuje spouštění těchto příkazů:
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 ...
… jehož účinkem je umožnit ccache zachytit všechny příkazy, které by jinak přešly na kompilátory, což umožňuje ccache vrátit soubor v mezipaměti nebo předat příkaz skutečnému kompilátoru.
sh
je symbolický odkaz nadash
. Chovají se jinak, když jsou voláni jakosh
nebo jakodash
busybox
(běžné na záchranných discích apod.), Pak je všechno (cp, mv, rm, ls, …) symbolickým odkazem na busybox.gcc
,bash
,gunzip
, většina ze zbytku OS …), protože Linux je pouze jádro.