Proč argv obsahuje název programu?

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

  • jako mv a cp?
  • Na Debianu sh je symbolický odkaz na dash. Chovají se jinak, když jsou voláni jako sh nebo jako dash
  • @AlexejMagura Pokud používáte něco jako busybox (běžné na záchranných discích apod.), Pak je všechno (cp, mv, rm, ls, …) symbolickým odkazem na busybox.
  • I ‚ mi připadá opravdu těžké ignorovat, takže ‚ ll řekni to: pravděpodobně myslíš “ GNU “ programy (gcc, bash, gunzip, většina ze zbytku OS …), protože Linux je pouze jádro.
  • @ wizzwizz4 Co je ‚ na “ typických programech pro Unix / Linux “ špatně? Četl jsem to jako “ Typické programy běžící na Unix / Linux „. To ‚ je mnohem lepší než vaše omezení na určité programy GNU. Dennis Ritchie rozhodně nepoužíval žádné programy GNU. BTW jádro Hurd je příkladem programu GNU, který nemá hlavní funkci …

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 a bzip2, 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] je sh. 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.

  • atd.
  • Komentáře

    • Další je sendmail a mail. 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). A tex, 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 , kde exec bere odkazy na štítek 2 a štítek 1 a na štítku 2: se objeví etc/init\0 a na štítku 1: se objeví odkaz na štítek 2 a koncová nula), což je v podstatě to, co execve dnes dělá minus envp.
    • execv a execl 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č :

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

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

    Zdroj a další informace .

    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.

    Napsat komentář

    Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *