Argv neden program adını içeriyor?


106

Tipik Unix / Linux programları komut satırı girişlerini argüman sayımı ( int argc) ve argüman vektörü ( char *argv[]) olarak kabul eder. İlk öğe argvprogramın adıdır - bunu asıl argümanlar izler.

Program adı neden yürütülebilir dosyaya bir argüman olarak aktarılıyor? Kendi adlarını kullanan herhangi bir program örneği var mı (belki bir tür execdurum)?


6
mv ve cp gibi?
Archemar

9
On Debian shbağlantıda dash. Olarak adlandırılan zaman onlar, farklı davranması shveyadash
Motte001

21
@AlexejMagura Gibi bir şey kullanırsanız busybox(kurtarma disklerinde ve benzeri), o zaman hemen hemen her şey (cp, mv, rm, ls, ...) meşgul kutusuna sembolik bir bağlantıdır.
Baard Kopperud

11
Bunu buluyorum gerçekten göz ardı etmek zor, bu yüzden söylüyorum: muhtemelen "GNU" programları ortalama ( gcc, bash, gunzip, OS ... geri kalanının çoğu), Linux sadece bir çekirdek olarak.
wizzwizz4

10
@ wizzwizz4 "Tipik Unix / Linux programları" ile ilgili sorun nedir? "Unix / Linux üzerinde çalışan tipik programlar" gibi okudum. Bu, bazı GNU programlarına yaptığınız kısıtlamadan çok daha iyidir. Dennis Ritchie kesinlikle herhangi bir GNU programı kullanmıyordu. BTW Hurd çekirdeği, ana işlevi olmayan bir GNU programına bir örnektir ...
rudimeier 13:16

Yanıtlar:


122

Başlamak için argv[0]mutlaka programın adı olmadığını unutmayın . Bu arayan içine koyar ne argv[0]ait execve(örneğin bkz sistem çağrısı Yığın taşması bu soruyu ). (Diğer tüm değişkenler execsistem çağrıları değil, arayüzleridir execve.)

Örneğin, aşağıdakileri (kullanarak execl) varsayalım :

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

/var/tmp/mybackdooridam edilen ancak argv[0]ayarlanan topşeydir ve bu psya da (gerçek) topgöstereceği şeydir . Bu konuda daha fazla bilgi için U&L SE'deki bu cevaba bakınız .

Kenara tüm bu ayarlanması: gibi fantezi dosya sistemleri gelişiyle önce /proc, argv[0]bir süreç, kendi isim hakkında bilgi edinmek için tek yol oldu. Bu ne için iyi olurdu?

  • Birkaç program, davranışlarını çağrıldıkları isme göre uyarlar (genellikle sembolik veya sabit linkler, örneğin BusyBox'un programları ; bu sorunun diğer cevaplarında birkaç örnek daha vardır).
  • Dahası, syslog aracılığıyla giriş yapan servisler, servis programları ve diğer programlar genellikle isimlerini günlük girişlerine hazırlar; Bu olmazsa, olay takibi olanaksız hale gelir.

18
Bu tür programların örnekleri bunzip2, bzcatve bzip2bunlar için ilk ikisi, üçüncü programa benzerler.
Ruslan,

5
@Ruslan İlginç zcatbir sembolik bağlantı değildir. Bunun yerine bir kabuk betiği kullanarak bu tekniğin olumsuz yönlerinden kaçınıyor gibiler. Ancak, tam bir --helpçıktı yazdırmayı başaramazlar, çünkü gzip için seçenekler ekleyen bir kişi de zcat'ı korumayı unuttu.
rudimeier,

1
Hatırlayabildiğim kadarıyla GNU kodlama standartları, program davranışını değiştirmek için argv [0] 'ın kullanılmasını önermemiştir ( şu anki sürümde "Genel Olarak Arayüzler için Standartlar" bölümü ). gunziptarihi bir istisnadır.

19
busybox başka bir mükemmel örnek. Farklı komutları çağırmak için 308 farklı isimler tarafından çağrılabilir: busybox.net/downloads/BusyBox.html#commands
Pepijn Schmitz

2
Pek çok, daha birçok program argv[0], isimlerini kodlama yerine kullanım / yardım çıktılarına enjekte eder . Bazıları tam, bazıları sadece temel ad.
spektrumlar

62

Bol:

  • Bash çalışan POSIX modunda iken argv[0]ise sh. Bu bir giriş kabuğu olarak çalışır argv[0]ile başlar -.
  • Olarak çalıştırıldığında um farklı davranır vi, view, evim, eview, ex, vimdiff, vs.
  • Daha önce de belirtildiği gibi Busybox.
  • İnit olarak systemd sistemlerde, içinde shutdown, rebootvb vardır sembolik bağlar içinsystemctl .
  • ve bunun gibi.

7
Bir diğeri sendmailve mail. Her bir unix MTA, bu iki komut için bir sembolik bağlantıya sahiptir ve bu şekilde çağrıldığında orijinalin davranışını taklit etmek için tasarlanmıştır, yani posta göndermesi gereken tüm unix programlarının tam olarak nasıl yapabileceklerini bildiği anlamına gelir.
Shadur

4
başka bir yaygın durum: testve [: ilkini çağırdığınızda, son bağımsız değişken ise bir hatayı ele alır ]. (gerçek Debian kararlı üzerinde bu komutlar iki farklı programdır, ancak önceki sürümler ve MacO'lar hala aynı programı kullanmaktadır). Ve tex, latexve benzeri: ikili aynıdır, ancak nasıl çağrıldığını bakarak, uygun yapılandırma dosyasını seçer . initbenzer.
Giacomo Catenazzi 12:16

4
İlgili, [son argüman ise bir hata gördüğü değil ] .
chepner,

Sanırım bu ikinci soruyu cevaplıyor, ancak ilk değil. Bazı işletim sistemi tasarımcılarının oturduğundan ve “Çalıştırılabilir ismine bağlı olarak aynı şeyleri aynı programla yapmam harika olurdu” dedi. Sanırım ismini argüman dizisine ekleyeceğim, daha sonra. «
Joey

@Joey Evet, ifadelerin bunu iletmesi amaçlanmıştır (S: "Herhangi bir ...?" "A:" Plenty: ... ")
muru

34

Tarihsel olarak, argvsadece komut satırının “sözcükleri” için bir işaretçi dizisidir, bu nedenle programın adı olan ilk “sözcük” ile başlamak mantıklıdır.

Ve onları adlandırmak için hangi ismin kullanıldığına göre farklı davranış gösteren oldukça az sayıda program vardır, böylece onlara sadece farklı bağlantılar oluşturabilir ve farklı “komutlar” alabilirsiniz. Aklıma gelen en uç örnektir busybox , denir nasıl bağlı olarak birkaç düzine farklı "komutları" gibi davranır .

Düzenleme : İstendiği gibi Unix 1. basım için referanslar

Bir gelen örneğin görebileceğiniz ana fonksiyonu ccolduğunu argcve argvzaten kullanıldı. Kabuk kopyalar argümanları parbufiçinde newargdöngünün bir parçası, bağımsız değişken olarak aynı şekilde olarak komutu tedavi ederken. (Tabii ki, daha sonra komutun adı olan sadece ilk argümanı yürütür). Öyle görünüyor execvve akrabaları yoktu.


1
lütfen bunu yedekleyen referanslar ekleyin.
lesmana 12:16

Hızlı bir kaymağını itibaren execyürütülecek komutun adını ve en iyi görülebilir karakter işaretçiler bir sıfır sonlandırılmış dizisi (sürer minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , nerede execalır etiket 2 ve etiket 1'e atıfta bulunur ve etikette 2:görünür etc/init\0ve etikette 1:etiket 2'ye bir referans ve sonlandırıcı bir sıfır) görünür, bu temel olarak execvebugün eksidir envp.
ninjalj,

1
execvve execl“sonsuza dek” var (yani, 1970'lerin başından bu yana) - execvbir sistem çağrısıydı ve execlonu adlandıran bir kütüphane işlevi idi.   execveyoktu, çünkü o zamanlar çevre yoktu. Ailenin diğer üyeleri daha sonra eklendi.
G-Man

@ G-Man execvBağlantılı olduğum v1 kaynağında beni gösterebilir misiniz? Sadece merak.
dirkt

22

Kullanım durumlarda:

Program davranışını değiştirmek için program adını kullanabilirsiniz .

Örneğin, gerçek ikili için bazı sembolik bağlantılar oluşturabilirsiniz.

Bu tekniğin kullanıldığı ünlü örneklerden biri, sadece bir ikili ve birçok sembolik bağlantı kuran yoğun kutu projesidir. (ls, cp, mv vb.) Hedefleri küçük gömülü aygıtlar olduğu için depolama alanı kazanmak için yapıyorlar .

Bu aynı zamanda setarchutil-linux'da da kullanılır :

$ 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

Burada birçok yinelenen kaynak dosyadan kaçınmak veya kaynakları daha okunaklı tutmak için bu tekniği kullanıyorlar .

Başka bir kullanım durumu, çalışma zamanında bazı modülleri veya verileri yüklemesi gereken bir program olabilir. Program yoluna sahip olmak, modülleri program konumuna göre bir yoldan yüklemenizi sağlar .

Ayrıca, birçok program program adı dahil hata mesajları yazdırır .

Neden :

  1. Çünkü POSIX konvansiyonu ( man 3p execve):

argv, yeni programa iletilen argüman dizelerinin bir dizisidir. Kurallara göre, bu dizelerin ilki, yürütülen dosyayla ilişkili dosya adını içermelidir.

  1. C standardıdır (en az C99 ve C11):

Argc değeri sıfırdan büyükse, argv [0] ile gösterilen dize program adını gösterir; argv [0] [0], program adı ana bilgisayar ortamında mevcut değilse, boş karakter olacaktır.

C Standardı "dosya adı" değil "program adı" yazdığını unutmayın.


3
Bu bağlantıya başka bir bağlantı noktasından ulaşırsanız, bu kırılmaz mı?
Mehrdad

3
@Mehrdad, Evet bu olumsuz ve kullanıcı için kafa karıştırıcı olabilir.
rudimeier,

@ rudimeier: 'Neden' öğeleriniz gerçekten sebep değil, sadece bir "homunculus" dır, yani standardın neden böyle olmasını gerektirdiği sorusu sorulur.
einpoklum

@ einpoklum OP'nin sorusu şuydu: Neden program adı yürütülebilir dosyaya geçiyor ? Cevap verdim: Çünkü POSIX ve C standardı bunu yapmamızı söylüyor. Bunun gerçekten bir sebep olmadığını nasıl düşünüyorsun ? Eğer alıntı yaptığım dokümanlar mevcut olmazsa, muhtemelen birçok program program adını geçemez.
rudimeier

OP etkili bir şekilde soruyor: "POSIX ve C standartları neden bunu söylüyor?" İfadenin soyutlanmış bir seviyede olduğu kabul edildi, ancak açık görünüyor. Gerçekçi olarak, bilmek için tek yol yaratıcılardan sormaktır.
user2338816

21

Nasıl çağrıldıklarına bağlı olarak davranışlarını değiştiren programlara ek olarak argv[0], bir programın kullanımını basarken de faydalı buluyorum :

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

Bu, kullanım iletisinin her zaman çağrıldığı adı kullanmasına neden olur. Program yeniden adlandırılırsa, kullanım mesajı onunla birlikte değişir. Hatta çağrıldığı yol adını da içerir:

# 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]

Özellikle her yerde yaşayabilecek küçük özel amaçlı araçlar / scriptler için hoş bir dokunuş.

Bu GNU araçlarında da yaygın bir uygulama gibi görünüyor, lsörneğin bakınız :

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

3
+1. Ben de aynısını önerecektim. Bu kadar çok insanın davranış değiştirmeye odaklanması ve muhtemelen en açık ve çok daha yaygın kullanımdan bahsetmemesi garip.
Vee,

5

Bir program, yazmaya çalıştırır: program_name0 arg1 arg2 arg3 ....

Bu nedenle, kabuk belirteci zaten bölmeli ve ilk belirteç zaten programın adıdır. Ve BTW böylece program tarafında ve kabukta aynı endeksleri vardır.

Bence bu sadece bir kolaylık numarasıydı (en başında) ve diğer cevaplarda gördüğünüz gibi, bu da çok kullanışlıydı, bu yüzden bu gelenek devam etti ve API olarak belirlendi.


4

Temelde argv, program adını içerir, böylece şöyle bir hata mesajı yazabilirsiniz prgm: file: No such file or directory:

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

2

Bunun uygulamasının bir başka örneği de, siz yazmayan bir şey yazana kadar ... kendini değiştiren bu program 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;
}

Açıkçası, eğer ilginç bir örnekse, bir tür kesinti, ancak bunun gerçek kullanımları olabileceğini düşünüyorum - örneğin, kendi hafıza alanını indirdiği veya değiştirdiği yeni bir sürümüyle yeniden yazan kendi kendini güncelleyen bir ikili.

Örnek:

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

7 | $

Kaynak ve biraz daha bilgi .


1000'e ulaştığınız için tebrikler.
G-Man

0

Programın yolu, programın argv[0]kurulum dizininden yapılandırma dosyalarını vb. Alabilmesidir.
Bu olmadan mümkün olmazdı argv[0].


2
Bu, özellikle iyi bir açıklama değil(char *path_to_program, char **argv, int argc)
olmamamız

Afaik, çoğu program standart bir yerden yapılandırma çekin ( ~/.<program>, /etc/<program, $XDG_CONFIG_HOME) ve ya bunu değiştirmek veya ikili sabit bir yer pişiren bir derleme zamanı seçeneği için bir parametre alır.
Xiong Chiamiov 17:16

0

ccache , derleyici ikili dosyalarına farklı çağrıları taklit etmek için bu şekilde davranır. ccache bir derleme önbelleğidir - asıl nokta hiçbir zaman aynı kaynak kodu iki kez derlememek değil, bunun yerine nesne kodunu önbellekten mümkünse geri döndürmektir.

Gönderen Ccache'in adam sayfasında , "ccache kullanmanın iki yolu vardır. Eğer derleme ccache ile komutları önüne isterseniz de. İlk yöntem (derleyici olarak adlandırılır) sembolik bir bağlantı Ccache'in için oluşturarak Ccache'in derleyici olarak taklit sağlayabilirsiniz ccache'yi denemek veya bazı belirli projeler için kullanmak istiyorsanız, ikinci bir yöntem tüm derlemeleriniz için ccache kullanmak istediğinizde kullanışlıdır. "

Symlinks yöntemi şu komutları çalıştırmayı içerir:

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

... bunun etkisi, önbelleğin, başka türlü derleyicilere giden komutları takmasına izin vermek, böylece önbelleğin önbelleğe alınmış bir dosyayı döndürmesini veya komutu gerçek derleyiciye iletmesini sağlamaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.