Argv में प्रोग्राम का नाम क्यों शामिल है?


106

विशिष्ट यूनिक्स / लिनक्स प्रोग्राम्स कमांड लाइन इनपुट्स को एक तर्क गणना ( int argc) और एक तर्क वेक्टर ( char *argv[]) के रूप में स्वीकार करते हैं । का पहला तत्व argvप्रोग्राम नाम है - वास्तविक तर्कों के बाद।

प्रोग्राम का नाम निष्पादन के लिए तर्क के रूप में क्यों दिया जाता है? क्या उनके स्वयं के नाम (शायद किसी प्रकार की execस्थिति) का उपयोग करके कार्यक्रमों के कोई उदाहरण हैं ?


6
एमवी और सीपी की तरह?
आर्चर

9
डेबियन shपर सहानुभूति है dash। वे अलग व्यवहार करते हैं, जब बुलाया जाता है shया जैसेdash
मोट्टे001

21
@AlexejMagura यदि आप busybox(बचाव-डिस्क और इस तरह के आम) पर कुछ का उपयोग करते हैं , तो बहुत ज्यादा सब कुछ (सीपी, एमवी, आरएम, एलएस, ...) बिजीबॉक्स का एक प्रतीकात्मक लिंक है।
कोपरपुड

11
मैं इस ढूँढने रहा हूँ वास्तव में अनदेखी करने के लिए मुश्किल है, इसलिए मैं यह कहूँगा: (आप शायद मतलब है "जीएनयू" कार्यक्रमों gcc, bash, gunzipओएस ... के बाकी के अधिकांश,), के रूप में लिनक्स सिर्फ गिरी है।
wizzwizz4

10
@ wizzwizz4 "विशिष्ट यूनिक्स / लिनक्स कार्यक्रमों" में क्या गलत है? मैंने इसे "यूनिक्स / लिनक्स पर चलने वाले विशिष्ट कार्यक्रम" की तरह पढ़ा। यह कुछ GNU कार्यक्रमों के लिए आपके प्रतिबंध से बहुत बेहतर है। डेनिस रिची निश्चित रूप से किसी भी जीएनयू कार्यक्रमों का उपयोग नहीं कर रहा था। BTW द हर्ड कर्नेल एक GNU प्रोग्राम का एक उदाहरण है जिसमें कोई मुख्य कार्य नहीं है ...
rudimeier

जवाबों:


122

शुरू करने के लिए, ध्यान दें कि argv[0]जरूरी नहीं कि कार्यक्रम का नाम है। यह क्या फोन करने वाले में डालता है argv[0]की execveसिस्टम कॉल (जैसे देखने स्टैक ओवरफ़्लो पर इस सवाल का )। (अन्य सभी वेरिएंट execसिस्टम कॉल नहीं हैं, लेकिन इन्टरफेस हैं execve।)

उदाहरण के लिए मान लीजिए, निम्नलिखित (उपयोग कर execl):

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

/var/tmp/mybackdoorजिसे निष्पादित argv[0]किया जाता है top, लेकिन उसे सेट किया जाता है , और यही वह ps(या वास्तविक) topप्रदर्शित होता है। इस पर अधिक के लिए U & L SE पर यह उत्तर देखें ।

इस सब को एक तरफ सेट करना: जैसे फैंसी फाइल सिस्टम के आने से पहले /proc, argv[0]एक प्रक्रिया के लिए अपने स्वयं के नाम के बारे में जानने का एकमात्र तरीका था। इससे अच्छा क्या होगा?

  • कई कार्यक्रम उनके व्यवहार को उस नाम के आधार पर अनुकूलित करते हैं जिसके द्वारा उन्हें बुलाया गया था (आमतौर पर प्रतीकात्मक या कठिन लिंक, उदाहरण के लिए बिजीबॉक्स की उपयोगिताओं ; इस प्रश्न के अन्य उत्तर में कई और उदाहरण प्रदान किए जाते हैं)।
  • इसके अलावा, सेवाओं, डेमोंस और अन्य प्रोग्राम जो कि syslog के माध्यम से लॉग करते हैं, अक्सर लॉग एंट्रीज में अपना नाम डालते हैं; इसके बिना, ईवेंट ट्रैकिंग संभव के बगल में हो जाएगी।

18
ऐसे कार्यक्रमों के उदाहरण हैं bunzip2, bzcatऔर bzip2, जिसके लिए पहले दो तीसरे के लिए सहानुभूति हैं।
रुस्लान

5
@Ruslan दिलचस्प बात zcatयह है कि सिमिलर नहीं है। वे इसके बजाय एक शेल स्क्रिप्ट का उपयोग करते हुए इस तकनीक के डाउनसाइड्स से बचते हैं। लेकिन वे एक पूर्ण --helpआउटपुट प्रिंट करने में विफल रहते हैं क्योंकि कोई व्यक्ति जो gzip में विकल्प जोड़ता है वह zcat को बनाए रखना भी भूल गया।
रुडाइमियर

1
जब तक मैं याद रख सकता हूं, GNU कोडिंग मानकों ने प्रोग्राम व्यवहार ( वर्तमान संस्करण में मानक "इंटरफेस के लिए मानक" ) को बदलने के लिए argv [0] के उपयोग को हतोत्साहित किया है । gunzipएक ऐतिहासिक अपवाद है।

19
बिजीबॉक्स एक और उत्कृष्ट उदाहरण है। इसे 308 अलग-अलग नामों से बुलाया जा सकता है अलग-अलग आदेशों को आमंत्रित करने के लिए: busybox.net/downloads/BusyBox.html#commands
Pepijn Schmitz

2
कई, कई और कार्यक्रम भी argv[0]उनके नाम को हार्ड-कोडिंग के बजाय उनके उपयोग / सहायता आउटपुट में इंजेक्ट करते हैं । कुछ में पूर्ण, कुछ में बस नाम।
स्पेक्ट्रा

62

बहुत सारे:

  • बैश POSIX मोड में है जब चलता argv[0]है sh। जब यह argv[0]शुरू होता है तो यह एक लॉगिन शेल के रूप में चलता है -
  • जब के रूप में चलाने विम अलग ढंग से व्यवहार करती है vi, view, evim, eview, ex, vimdiff, आदि
  • बिजीबॉक्स, जैसा कि पहले ही उल्लेख किया गया है।
  • Init के रूप में systemd साथ प्रणालियों में shutdown, rebootआदि कर रहे हैं करने के लिए सिमलिंकsystemctl
  • और इसी तरह।

7
एक और एक है sendmailऔर mail। हर एक यूनिक्स एमटीए उन दो आदेशों के लिए एक सिम्लिंक के साथ आता है, और मूल के व्यवहार को अनुकरण करने के लिए डिज़ाइन किया गया है, जैसे कि, इसका मतलब है कि किसी भी यूनिक्स प्रोग्राम को मेल भेजने की आवश्यकता है, जो वास्तव में जानते हैं कि वे ऐसा कैसे कर सकते हैं।
शादुर

4
एक अन्य सामान्य मामला: testऔर [: जब आप पूर्व कॉल करते हैं, तो यह एक त्रुटि को संभालता है यदि अंतिम तर्क है ]। (वास्तविक डेबियन स्थिर पर ये कमांड दो अलग-अलग प्रोग्राम हैं, लेकिन पिछले संस्करण और मैकओ अभी भी एक ही प्रोग्राम का उपयोग करते हैं)। और tex, latexऔर इसी तरह: बाइनरी एक ही है, लेकिन यह देखते हुए कि इसे कैसे बुलाया गया था, यह उचित कॉन्फ़िगरेशन फ़ाइल का चयन करता है । initसमान है।
जियाकोमो कैटेनज़ज़ी

4
संबंधित, [इसे एक त्रुटि मानता है यदि अंतिम तर्क नहीं है ]
शेपनर

मुझे लगता है कि यह दूसरे प्रश्न का उत्तर देता है, लेकिन पहला नहीं। मुझे बहुत संदेह है कि कुछ ओएस डिजाइनर बैठ गए और कहा »अरे, यह अच्छा होगा अगर मेरे पास एक ही कार्यक्रम अलग-अलग चीजें कर रहा था जो कि इसके निष्पादन योग्य नाम पर आधारित है। मुझे लगता है कि मैं इसके तर्क सरणी में नाम शामिल करूंगा, फिर। «
जॉय

@ जॉय हाँ, शब्द का अर्थ यह बताना है कि (Q: "क्या कोई है ...?" A: "भरपूर: ...")
muru

34

ऐतिहासिक रूप से, argvकमांडलाइन के "शब्दों" के लिए केवल एक व्यूअर है, इसलिए यह पहले "शब्द" के साथ शुरू करने के लिए समझ में आता है, जो कार्यक्रम का नाम होता है।

और काफी कुछ प्रोग्राम हैं जो अलग-अलग व्यवहार करते हैं जिसके अनुसार उन्हें कॉल करने के लिए नाम का उपयोग किया जाता है, इसलिए आप बस उनके लिए अलग-अलग लिंक बना सकते हैं और अलग-अलग "कमांड" प्राप्त कर सकते हैं। सबसे चरम उदाहरण मैं सोच सकता हूं कि बिजीबॉक्स है , जो कई दर्जन अलग-अलग "कमांड" की तरह काम करता है जो इस बात पर निर्भर करता है कि इसे कैसे कहा जाता है

संपादित करें : अनुरोध के अनुसार यूनिक्स 1 संस्करण के लिए संदर्भ

एक से जैसे देख सकते हैं मुख्य के समारोह ccहै कि argcऔर argvपहले से ही इस्तेमाल किया गया। खोल करने के लिए प्रतियां तर्क parbufअंदर newargपाश का हिस्सा है, जबकि तर्क के रूप में एक ही तरीके से आदेश ही इलाज। (बेशक, बाद में यह केवल पहले तर्क को निष्पादित करता है, जो कमांड का नाम है)। ऐसा लगता है कि execvरिश्तेदारों का अस्तित्व ही नहीं था।


1
कृपया इस संदर्भ को वापस जोड़ें।
lesmana

एक त्वरित स्किमिंग से, execआदेश पर अमल करने के नाम पर और चार संकेत के एक शून्य समाप्त सरणी (सबसे अच्छे रूप में देखा लेता minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , जहां execले जाता है लेबल 2 और लेबल 1 के संदर्भ, और लेबल पर 2:प्रकट होता है etc/init\0, और लेबल 1:पर लेबल 2 का संदर्भ और शून्य समाप्त होता है), जो मूल रूप execveसे आज शून्य से है envp
नवजलज

1
execvऔर execl"हमेशा के लिए" अस्तित्व में है (यानी, 1970 के दशक के मध्य के बाद से) - execvएक सिस्टम कॉल execlथा और एक पुस्तकालय फ़ंक्शन था जिसने इसे बुलाया।   execveतब मौजूद नहीं था क्योंकि पर्यावरण तब मौजूद नहीं था। परिवार के अन्य सदस्यों को बाद में जोड़ा गया था।
जी-मैन

@ G-Man क्या आप मुझे मेरे द्वारा execvजोड़े गए v1 स्रोत में इंगित कर सकते हैं ? बस उत्सुक।
6

22

बक्सों का इस्तेमाल करें:

प्रोग्राम के व्यवहार को बदलने के लिए आप प्रोग्राम के नाम का उपयोग कर सकते हैं ।

उदाहरण के लिए, आप वास्तविक बाइनरी के लिए कुछ सहानुभूति बना सकते हैं।

एक प्रसिद्ध उदाहरण जहां इस तकनीक का उपयोग किया जाता है वह बिजीबॉक्स प्रोजेक्ट है जो केवल एक ही बाइनरी स्थापित करता है और कई सिम्लिंक करता है। (ls, cp, mv, आदि)। वे भंडारण स्थान को बचाने के लिए ऐसा कर रहे हैं क्योंकि उनके लक्ष्य छोटे एम्बेडेड डिवाइस हैं।

इसका उपयोग उपयोग setarch-लिनेक्स से भी किया जाता है :

$ 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

यहां वे मूल रूप से कई डुप्लिकेट स्रोत फ़ाइलों से बचने या स्रोतों को अधिक पठनीय रखने के लिए इस तकनीक का उपयोग कर रहे हैं ।

एक अन्य उपयोग मामला एक प्रोग्राम होगा जिसमें रनटाइम पर कुछ मॉड्यूल या डेटा लोड करने की आवश्यकता होती है। प्रोग्राम पथ होने से आप प्रोग्राम स्थान के सापेक्ष एक पथ से मॉड्यूल लोड कर सकते हैं ।

इसके अलावा कई कार्यक्रम प्रोग्राम नाम सहित त्रुटि संदेश प्रिंट करते हैं

क्यों :

  1. क्योंकि यह POSIX सम्मेलन ( man 3p execve):

argv नए प्रोग्राम में दिए गए तर्क स्ट्रिंग का एक सरणी है। कन्वेंशन द्वारा, इन स्ट्रिंग्स में से सबसे पहले फ़ाइल नाम से संबंधित फ़ाइल नाम निष्पादित होना चाहिए।

  1. यह C मानक (कम से कम C99 और C11):

यदि argc का मान शून्य से अधिक है, तो argv द्वारा इंगित स्ट्रिंग [0] कार्यक्रम के नाम का प्रतिनिधित्व करती है; यदि प्रोग्राम का नाम होस्ट वातावरण से उपलब्ध नहीं है, तो argv [0] [0] शून्य वर्ण होगा।

नोट सी मानक "प्रोग्राम का नाम" नहीं "फ़ाइल नाम" कहता है।


3
यदि आप किसी अन्य सिमलिंक से सिम्कलिन तक पहुँचते हैं तो क्या यह विराम नहीं है?
मेहरदाद

3
@ मेहरदाद, हाँ यह नकारात्मक पहलू है और उपयोगकर्ता के लिए भ्रामक हो सकता है।
रुडाइमियर

@rudimeier: आपके 'क्यों' आइटम वास्तव में कारण नहीं हैं, वे सिर्फ एक "होम्युनकुलस" हैं, अर्थात यह सिर्फ इस सवाल का जवाब देता है कि मानक को इस मामले की आवश्यकता क्यों है।
einpoklum

@einpoklum ओपी का सवाल था: कार्यक्रम का नाम निष्पादन योग्य को क्यों दिया गया है? मैंने उत्तर दिया: क्योंकि POSIX और C मानक हमें ऐसा करने के लिए कहते हैं। आप कैसे सोचते हैं कि यह वास्तव में एक कारण नहीं है ? यदि मैंने जो डॉक्स उद्धृत किया है वह मौजूद नहीं होता तो शायद कई प्रोग्राम प्रोग्राम का नाम नहीं देते।
रदिमीयर

ओपी प्रभावी रूप से पूछ रहा है कि "POSIX और C मानक ऐसा करने के लिए क्यों कहते हैं?" दी शब्दांकन एक सार स्तर पर था, लेकिन यह स्पष्ट लगता है। वास्तविक रूप से, जानने का एकमात्र तरीका यह है कि प्रवर्तकों से पूछा जाए।
user2338816

21

उनके व्यवहार को बदलने के कार्यक्रमों के अलावा, उन्हें कैसे बुलाया गया था, मुझे argv[0]प्रोग्राम के उपयोग को प्रिंट करने में उपयोगी लगता है, जैसे:

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

यह उपयोग संदेश को उस नाम का हमेशा उपयोग करने का कारण बनता है जिसके माध्यम से उसे बुलाया गया था। यदि प्रोग्राम का नाम बदला जाता है, तो इसके उपयोग का संदेश इसके साथ बदल जाता है। इसमें वह पथ नाम भी शामिल है जिसे इसके साथ बुलाया गया था:

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

यह एक अच्छा स्पर्श है, विशेष रूप से छोटे विशेष प्रयोजन के उपकरण / स्क्रिप्ट के लिए जो सभी जगह पर रह सकते हैं।

यह जीएनयू उपकरणों में सामान्य अभ्यास लगता है, 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.

3
+1। मैं उसी का सुझाव देने जा रहा था। अजीब बात है कि इतने सारे लोग बदलते व्यवहार पर ध्यान केंद्रित करते हैं और संभवतः सबसे स्पष्ट और अधिक व्यापक उपयोग का उल्लेख करने में विफल होते हैं।
Vee

5

एक कार्यक्रम टाइपिंग निष्पादित करता है program_name0 arg1 arg2 arg3 ...:।

तो शेल को पहले से ही टोकन को विभाजित करना चाहिए, और पहला टोकन पहले से ही प्रोग्राम का नाम है। और BTW इसलिए प्रोग्राम साइड और शेल पर समान सूचकांक हैं।

मुझे लगता है कि यह केवल एक सुविधा चाल थी (बहुत शुरुआत में), और, जैसा कि आप अन्य उत्तरों में देखते हैं, यह बहुत आसान भी था, इसलिए इस परंपरा को जारी रखा गया और एपीआई के रूप में सेट किया गया।


4

मूल रूप से, argv में प्रोग्राम का नाम शामिल है ताकि आप त्रुटि संदेश लिख सकें prgm: file: No such file or directory, जैसे कि इसे कुछ इस तरह से लागू किया जाएगा:

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

2

इसका एक और उदाहरण इस कार्यक्रम का है, जो अपने आप को ... खुद के साथ बदल देता है, जब तक आप कुछ ऐसा नहीं लिखते हैं 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;
}

जाहिर है, दिलचस्प उदाहरण अगर किसी प्रकार का होता है, लेकिन मुझे लगता है कि इसके वास्तविक उपयोग हो सकते हैं - उदाहरण के लिए, एक सेल्फ-अपडेटिंग बाइनरी, जो स्वयं के नए संस्करण के साथ अपनी मेमोरी स्पेस को फिर से लिखता है जिसे उसने डाउनलोड किया या बदल दिया।

उदाहरण:

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

7 | $

स्रोत, और कुछ और जानकारी


1000 तक पहुंचने पर बधाई।
जी-मैन

0

प्रोग्राम का पथ है argv[0], ताकि प्रोग्राम अपनी इंस्टॉल डायरेक्टरी से कॉन्फ़िगरेशन फाइल्स आदि को पुनः प्राप्त कर सके।
इसके बिना यह असंभव होगा argv[0]


2
यह एक विशेष रूप से अच्छी व्याख्या नहीं है - ऐसा कोई कारण नहीं है कि हम (char *path_to_program, char **argv, int argc)उदाहरण के लिए कुछ पर मानकीकृत नहीं कर सकते हैं
मोपेट

AFAIK, ज्यादातर कार्यक्रमों के लिए एक मानक स्थान से विन्यास खींच ( ~/.<program>, /etc/<program, $XDG_CONFIG_HOME) और या तो एक पैरामीटर यह बदलने के लिए या एक संकलन समय विकल्प है कि बाइनरी में एक निरंतर में bakes है।
Xiong Chiamiov

0

संकलक बायनेरिज़ के लिए विभिन्न कॉलों की नकल करने के लिए ccache इस तरह से व्यवहार करता है। ccache एक संकलन कैश है - संपूर्ण बिंदु कभी भी एक ही स्रोत कोड को दो बार संकलित करने के लिए नहीं है, बल्कि यदि संभव हो तो कैश से ऑब्जेक्ट कोड लौटाएं।

से ccache आदमी पेज , "वहाँ ccache का उपयोग करने के दो तरीके हैं। आप उपसर्ग या तो कर सकते हैं अपने संकलन ccache साथ आदेशों या आप एक प्रतीकात्मक कड़ी (संकलक के रूप में नामित) ccache करने के लिए। पहली विधि बनाने के द्वारा ccache संकलक का छद्मवेष दे सकते हैं यदि आप केवल ccache को आज़माना चाहते हैं या कुछ विशिष्ट परियोजनाओं के लिए इसका उपयोग करना चाहते हैं तो सबसे सुविधाजनक है। जब आप अपनी सभी संकलनों के लिए ccache का उपयोग करना चाहते हैं तो दूसरी विधि सबसे उपयोगी है। "

सिमिलिंक विधि में ये कमांड चलाना शामिल हैं:

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

... जिसका प्रभाव ccache को किसी भी कमांड को स्नैग करने की अनुमति देना है जो अन्यथा संकलक के पास जाएगा, इस प्रकार ccache को कैश्ड फ़ाइल को वापस करने या वास्तविक कंपाइलर पर कमांड को पारित करने की अनुमति मिलती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.