argv에 프로그램 이름이 포함 된 이유는 무엇입니까?

일반적인 Unix / Linux 프로그램은 명령 줄 입력을 인수 개수 (int argc) 및 인수 벡터로 허용합니다. (char *argv[]). argv의 첫 번째 요소는 실제 인수가 뒤 따르는 프로그램 이름입니다.

프로그램 이름이 실행 파일에 인수로 전달되는 이유는 무엇입니까? 자신의 이름을 사용하는 프로그램의 예가 있습니까 (예 : exec 상황)?

댓글

  • 예 : mv 및 cp?
  • Debian에서 shdash에 대한 심볼릭 링크입니다. sh 또는 dash
  • 로 호출 될 때 다르게 작동합니다.

  • @AlexejMagura

    (rescue-discs 등에서 공통), 거의 모든 (cp, mv, rm, ls, …)은 busybox에 대한 심볼릭 링크입니다.

  • ‘이 문제를 정말 무시하기 어렵다고 생각하므로 ‘ 말하세요 : 아마도 ” GNU ” 프로그램 (gcc, bash, gunzip, 나머지 OS의 대부분 …) Linux는 커널 일뿐입니다.
  • @ wizzwizz4 ‘ ” 일반적인 Unix / Linux 프로그램 “의 문제점은 무엇입니까? ” Unix / Linux에서 실행되는 일반적인 프로그램 “처럼 읽었습니다. 특정 GNU 프로그램에 대한 제한보다 ‘ 훨씬 낫습니다. Dennis Ritchie는 확실히 GNU 프로그램을 사용하지 않았습니다. BTW the Hurd 커널은 주요 기능이없는 GNU 프로그램의 예입니다 …

Answer

먼저 argv[0]가 프로그램 이름 일 필요는 없습니다. 호출자가 execve 시스템 호출의 argv[0]에 입력 한 내용입니다 (예 : 참조). 이 질문은 Stack Overflow )에 있습니다. (exec의 다른 모든 변형은 시스템 호출이 아니라 execve에 대한 인터페이스입니다.)

예를 들어, 다음 (execl 사용) :

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

/var/tmp/mybackdoor는 실행되지만 argv[0]top로 설정되어 있으며 ps 또는 ( 실제) top가 표시됩니다. 이에 대한 자세한 내용은 U & L SE에서 이 답변 을 참조하세요.

모두 설정 이건 제쳐두고 : /proc와 같은 멋진 파일 시스템이 등장하기 전에는 argv[0]가 프로세스가 자신의 이름을 알 수있는 유일한 방법이었습니다. 그게 무엇에 좋을까요?

  • 여러 프로그램은 이름에 따라 동작을 사용자 지정합니다 (보통 기호 또는 하드 링크 (예 : BusyBox의 유틸리티 ;이 질문에 대한 다른 답변에서 몇 가지 더 많은 예제가 제공됩니다.
  • 또한 syslog를 통해 기록하는 서비스, 데몬 및 기타 프로그램은 종종 이름 앞에 이름을 추가합니다. 로그 항목이 없으면 이벤트 추적이 거의 불가능 해집니다.

댓글

  • 이러한 프로그램의 예는 bunzip2, bzcatbzip2. 처음 두 개는 세 번째 항목에 대한 심볼릭 링크입니다.
  • @Ruslan 흥미롭게도 zcat는 심볼릭 링크가 아닙니다. 대신 쉘 스크립트를 사용하여이 기술의 단점을 피하는 것 같습니다. 그러나 완전한 출력은 gzip에 옵션을 추가 한 누군가가 main zcat도 포함합니다.
  • 기억할 수있는 한 GNU 코딩 표준은 프로그램 동작을 변경하기 위해 argv [0] 사용을 권장하지 않습니다 ( 섹션 ” 일반적인 인터페이스 표준 ” 현재 버전 ). gunzip는 역사적 예외입니다.
  • busybox는 또 다른 훌륭한 예입니다. 다양한 명령을 호출하기 위해 308 개의 다른 이름으로 호출 할 수 있습니다. busybox.net/downloads/BusyBox.html#commands
  • 다양한 더 많은 프로그램이 이름을 하드 코딩하는 대신 사용 / 도움말 출력에 argv[0]를 삽입합니다. 일부는 완전하고 일부는 기본 이름입니다.

답변

많음 :

  • 배시는 argv[0]sh 일 때 POSIX 모드 에서 실행됩니다. argv[0]-로 시작하면 로그인 셸로 실행됩니다.
  • Vim은 vi, view, evim, eview, ex, vimdiff
  • 이미 언급했듯이 Busybox.
  • systemd가 init 인 시스템에서 shutdown, reboot 등은 systemctl 에 대한 기호 링크.
  • 등.

댓글

  • 다른 하나는 sendmailmail입니다. 모든 단일 유닉스 MTA는이 두 명령에 대한 심볼릭 링크와 함께 제공되며, 그렇게 호출 될 때 원래 ‘의 동작을 에뮬레이트하도록 설계되었습니다. 즉, 메일을 보내야하는 모든 유닉스 프로그램은 정확히 어떻게 할 수 있는지.
  • 다른 일반적인 경우 : test[ : 전자에 전화를 걸 때 , 마지막 인수가 ]이면 오류를 처리합니다. (실제 데비안 안정에서이 명령은 두 개의 다른 프로그램이지만 이전 버전과 MacO는 여전히 동일한 프로그램을 사용합니다). 그리고 tex, latex 등 : 바이너리는 동일하지만 호출 방법을 보면 적절한 구성 파일. init는 유사합니다.
  • 관련, [는 마지막 인수가 아닌 경우 ].
  • 두 번째 질문에 대한 답인 것 같지만 첫 번째 질문은 아닙니다. 일부 OS 디자이너가 자리에 앉아서 » 이봐, 같은 프로그램이 실행 파일 이름에 따라 다른 작업을 수행한다면 멋질 것 같습니다. ‘ 인수 배열에 이름을 포함 할 것 같습니다. «
  • @Joey 예, 문구는이를 전달하기위한 것입니다 (Q : ” …? ” A : ” 많음 : … “)

답변

역사적으로 argv는 명령 줄의 “단어”에 대한 포인터 배열 일 뿐이므로 첫 번째 “단어”로 시작하는 것이 좋습니다. 프로그램의 이름.

그리고 호출에 사용되는 이름에 따라 다르게 작동하는 프로그램이 꽤 있습니다. 따라서 다른 링크를 만들고 다른 “명령”을 얻을 수 있습니다. 제가 생각할 수있는 가장 극단적 인 예는 busybox 입니다. 는 방법에 따라 수십 개의 다른 “명령”처럼 작동합니다. 이름은 입니다.

수정

: 요청 된 Unix 1st 에디션에 대한 참조

예를 들어 볼 수 있습니다. argc 및 의 main 기능에서 = “036c143247”> 는 이미 사용되었습니다. 은 인수를 newarg 부분 내부의 parbuf에 복사합니다. 명령 자체를 인수와 동일한 방식으로 처리하는 동안 루프. (물론 나중에 명령의 이름 인 첫 번째 인수 만 실행합니다.) execv 인 것 같고 친척은 당시 존재하지 않았습니다.

댓글

  • 이를 백업합니다.
  • 빠른 훑어보기에서 exec는 실행할 명령의 이름과 0으로 끝나는 char 포인터 배열을 가져옵니다 ( minnie.tuhs.org/cgi-bin/utree.pl?file=V1/u0.s , 여기서 exec 레이블 2와 레이블 1에 대한 참조를 취하고 레이블 2:etc/init\0가 표시되고 레이블 1:는 라벨 2에 대한 참조로 나타나며 끝은 0)이며, 기본적으로 execve에서 오늘 수행하는 작업에서 envp를 뺀 것입니다. li>
  • execvexecl는 ” 영원히 (즉, 1970 년대 초반부터 중반까지) — execv는 시스템 호출이고 는 그것을 호출 한 라이브러리 함수였습니다. execve는 그 당시 환경이 존재하지 않았기 때문에 ‘ 존재하지 않았습니다. ‘ 다른 가족 구성원은 나중에 추가되었습니다.
  • @ G-Man 제가 연결 한 v1 소스의 execv를 알려 주시겠습니까? 궁금하세요.

답변

사용 사례 :

프로그램 이름 을 사용하여 프로그램 동작을 변경할 수 있습니다. .

예를 들어 실제 바이너리에 대한 심볼릭 링크를 만들 수 있습니다.

이 기술이 사용되는 유명한 예는 하나의 바이너리와 많은 심볼릭 링크를 설치하는 busybox 프로젝트입니다. (ls, cp, mv 등). 타겟이 소형 임베디드 기기이기 때문에 저장 공간을 절약하기 위해 작업을 수행하고 있습니다.

이것도 마찬가지입니다. util-linux의 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의 값이 0보다 크면 argv [0이 가리키는 문자열 ]는 프로그램 이름을 나타냅니다. argv [0] [0]은 호스트 환경에서 프로그램 이름을 사용할 수없는 경우 null 문자입니다.

C 표준에 “program name “은”filename “이 아닙니다.

댓글

  • ‘ 다른 심볼릭 링크의 심볼릭 링크입니까?
  • @Mehrdad, 그렇습니다. ‘ 단점이 있으며 사용자에게 혼란을 줄 수 있습니다.
  • @rudimeier : ‘ 왜 ‘ 항목이 실제로 이유가 아니라 ‘ 그냥 ” homunculus “, 즉 표준에서 왜 이것이 사실인지에 대한 질문을 던집니다.
  • @ einpoklum OP ‘의 질문은 다음과 같습니다. 프로그램 이름이 실행 파일에 전달됩니까? 나는 대답했다 : POSIX와 C 표준이 그렇게하라고하기 때문이다. ‘이 정말 이유 가 아니라고 어떻게 생각하십니까? 내가 인용 한 문서가 ‘ 존재하지 않는다면 많은 프로그램이 프로그램 이름을 전달하지 못할 것입니다.
  • OP는 효과적으로 ” POSIX 및 C 표준에서이를 수행하는 이유는 무엇입니까? ” 표현이 추상적 인 수준에 있었지만 분명해 보입니다. 현실적으로 알 수있는 유일한 방법은 작성자에게 물어 보는 것입니다.

답변

호출 된 방식에 따라 동작하는 경우 다음과 같이 프로그램 사용을 인쇄하는 데 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] 

그것은 특히 모든 곳에 살 수있는 작은 특수 목적 도구 / 스크립트에 대한 좋은 터치입니다.

이것은 GNU 도구에서도 일반적인 관행 인 것 같습니다. 예를 들어 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. 

댓글

  • +1. 동일한 제안을하려고했습니다. 이상하게도 많은 사람들이 행동 변화에 집중하고 아마도 가장 분명하고 훨씬 더 널리 사용됩니다.

Answer

하나는 프로그램 입력을 실행합니다. program_name0 arg1 arg2 arg3 ....

따라서 쉘은 이미 토큰을 분할해야하고 첫 번째 토큰은 이미 프로그램 이름입니다. 그리고 BTW는 프로그램 측과 쉘에 동일한 색인이 있습니다.

나는 이것이 단지 편의 트릭 (아주 처음에) 일 뿐이라고 생각하고, 다른 답변에서 볼 수 있듯이 매우 편리했기 때문에이 전통은 계속되었습니다. et as API.

Answer

기본적으로 argv에는 prgm: file: No such file or directory, 다음과 같이 구현됩니다.

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

Answer

이 프로그램의 또 다른 예는 “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 | $ 

출처 및 기타 정보 .

댓글

  • 1,000 명 달성을 축하합니다.

답변

프로그램의 경로는 argv[0]이므로 프로그램이 설치 디렉토리에서 구성 파일 등을 검색합니다.
argv[0] 없이는 불가능합니다.

댓글

  • ‘별로 좋은 설명이 아닙니다. ‘ 우리가 할 수없는 이유가 없습니다. ‘ 예를 들어 (char *path_to_program, char **argv, int argc)와 같은 것으로 표준화되지 않았습니다.
  • Afaik, 대부분의 프로그램은 표준 위치 (~/.<program>, /etc/<program, $XDG_CONFIG_HOME ) 매개 변수를 사용하여 변경하거나 바이너리에 상수를 베이크하는 컴파일 시간 옵션을 갖습니다.

Answer

ccache 는 모방하기 위해 이러한 방식으로 작동합니다. 컴파일러 바이너리에 대한 다른 호출. ccache는 컴파일 캐시입니다. 요점은 동일한 소스 코드를 두 번 컴파일하지 않고 가능한 경우 캐시에서 개체 코드를 반환하는 것입니다.

에서 ccache man page , “ccache를 사용하는 두 가지 방법이 있습니다. 컴파일 명령에 ccache를 접두사로 붙이거나 ccache에 대한 심볼릭 링크 (컴파일러로 명명 됨)를 생성하여 ccache가 컴파일러로 가장하도록 할 수 있습니다. 첫 번째 방법은 ccache를 사용해 보거나 특정 프로젝트에 사용하려는 경우 가장 편리합니다. 두 번째 방법은 모든 컴파일에 ccache를 사용하려는 경우에 가장 유용합니다. “

The symlinks 메소드는 다음 명령을 실행하는 것을 포함합니다 :

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가 캐시 된 파일을 반환하거나 실제 컴파일러에 명령을 전달할 수 있습니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다