답변:
변수는 쉘에서 세 가지 다른 변수 중 하나입니다.
_
또는 0 개 이상의 문자, 숫자 또는 다음 편지, _
.$1
, $2
...$0
, 그들은 모두 다양한 문장 부호입니다.set
쉘 변수 만 표시합니다.
쉘 변수의 서브 세트는 환경 변수로, 쉘이 시작될 때 환경에서 값이 상속되거나 export
유효한 이름으로 속성을 설정하여 작성됩니다 .
set
표시의 모든 매개 변수 zsh
(하지 $ 1, $ ... 2 만 $ *, $ @)와 떠들썩한 파티와 보쉬의 기능을합니다. ksh93과 같은 일부 쉘 및 쉘 변수에 맵핑되지 않은 이전 버전의 대시 출력 env vars. ( env 1=foo ksh -c set
인쇄 것 1=foo
)
$INTEGER
변수 유형에 대해 논의하기 전에 변수가 실제로 무엇이고 환경 변수와 어떻게 다른지 이해해야합니다 $INTEGER
. 이것은 POSIX (Portable Operating System Interface) 표준, 섹션 2.1 (강조 광산)에 설명되어 있습니다.
- 쉘은 함수 (함수 정의 명령 참조), 내장 (특수 내장 유틸리티 참조), 실행 파일 또는 스크립트를 실행 하여 인수의 이름을 1-n까지의 위치 매개 변수로 지정하고 명령 이름을 제공합니다. (또는 스크립트 내의 함수 인 경우 스크립트 이름)는 위치 매개 변수 번호가 0입니다 (명령 검색 및 실행 참조).
이와는 대조적으로, 같은 변수 $HOME
와 $PATH
환경 변수이다. 그들의 정의는 표준의 섹션 8에 설명되어 있습니다 .
이 장에서 정의 된 환경 변수는 여러 유틸리티, 기능 및 응용 프로그램의 작동에 영향을줍니다. 특정 유틸리티에만 관심이있는 다른 환경 변수가 있습니다. 단일 유틸리티에만 적용되는 환경 변수는 유틸리티 설명의 일부로 정의됩니다.
그들의 설명을 주목하십시오. 위치 매개 변수는 명령 앞에 나타납니다 (예 :) command positional_arg_1 positional_arg_2...
. 명령은 사용자가 구체적으로해야 할 일을 알려주기 위해 제공됩니다. 당신이 할 때 echo 'Hello' 'World'
, Hello
그리고 당신이 작업하고자하는 것들에 대한 World
위치 매개 변수이기 때문에 및 문자열을 인쇄 합니다. 그리고 위치 매개 변수를 인쇄 할 문자열로 이해하도록 작성되었습니다 (이와 같은 선택적 플래그 중 하나가 아닌 한 ). 당신이 다른 명령으로이 작업을 수행 할 경우 이해하지 않을 수 있습니다 무엇을 하고echo
echo
echo
-n
Hello
World
아마도 숫자를 기대하기 때문입니다. 위치 매개 변수는 "상속"되지 않습니다. 자식 프로세스는 자식 프로세스에 명시 적으로 전달되지 않는 한 부모의 위치 매개 변수에 대해 알지 못합니다. 종종 래퍼 스크립트와 함께 위치 매개 변수가 전달되는 것을 볼 수 있습니다. 이미 존재하는 명령 인스턴스를 확인하거나 호출 될 실제 명령에 추가 위치 매개 변수를 추가 할 수 있습니다.
반대로 환경 변수는 여러 프로그램에 영향을 미칩니다. 그것들은 프로그램 자체 밖에서 설정되기 때문에 환경 변수입니다 (자세한 내용은 아래 참조). 같은 특정 환경 변수 HOME
또는 PATH
특정 형식, 특별한 의미를 가지고 있고, 그들은 각 프로그램에 동일한 의미하는 것이다. HOME
변수는 외부 /usr/bin/find
쉘이나 쉘 과 같은 외부 유틸리티와 같 으며 (따라서 스크립트와 동일) 프로세스가 실행되는 사용자 이름의 홈 디렉토리입니다. 예를 들어 환경 변수를 사용하여 특정 명령 동작을 설명 할 수 있습니다.UID
환경 변수를 사용하여 스크립트가 루트 권한으로 실행되는지 여부를 확인하고 그에 따라 특정 작업으로 분기 할 수 있습니다. 환경 변수는 상속 가능합니다. 자식 프로세스는 부모 환경의 복사본을 얻습니다. 참조 프로세스가 부모의 환경을 상속하는 경우, 왜 우리가 수출해야합니까?
간단히 말해서, 주요 차이점은 환경 변수가 명령 외부에 설정되어 있으며 (대개) 변경되지 않는 반면, 위치 매개 변수는 명령에 의해 처리되고 변경되는 것입니다.
내가 의견에서 주목 한 것은 터미널과 셸을 혼합하고 있으며 한때 물리적 장치였던 실제 터미널 에 대해 읽는 것이 좋습니다 . 오늘날 우리가 일반적으로 언급하는 "터미널"은 검은 색 배경과 녹색 텍스트가있는 창은 실제로 소프트웨어이며 프로세스입니다. 터미널은 쉘을 실행하는 프로그램이지만 쉘은 프로그램이지만 실행하기 위해 입력 한 내용을 읽는 프로그램입니다 (즉, 대화식 쉘인 경우 비 대화식 쉘은 스크립트 및 sh -c 'echo foo'
호출 유형 임). 포탄에 대한 자세한 내용은 여기를 참조하십시오 .
이것은 중요한 차이점이지만 터미널이 프로그램임을 인식하고 동일한 환경 규칙 및 위치 매개 변수를 준수해야합니다. 당신의 gnome-terminal
당신 볼 것이다 시작된 SHELL
환경 변수, 당신은 몇 가지 다른 명령을 지정하지 않는 한, 당신을 위해 적절한 기본 쉘을 산란 -e
. 기본 쉘을 ksh
-gnome-terminal 로 바꾸고 ksh
대신에 스폰 한다고 가정 해 봅시다 bash
. 그것은 또한 프로그램이 환경을 사용하는 방법의 예입니다. 내가 명시 적으로 말할 경우 gnome-terminal
에 -e
특정 쉘을 실행 - 그것은 그것을 할 것입니다,하지만 영구적으로하지 않습니다. 대조적으로, 환경은 대부분 변경되지 않아야합니다 (나중에 자세히 설명).
보시다시피, 환경 및 위치 변수는 모두 쉘이 아닌 프로세스 / 명령의 속성입니다. 쉘 스크립트는 C 프로그래밍 언어로 설정된 모델을 따릅니다. 예를 들어 main
일반적으로 보이는 C 함수 를 예로 들어 보겠습니다.
int main(int argc, char **argv)
(여기서 argc
명령 줄 인수의 수이며, argv
효과적으로 명령 줄 매개 변수의 배열이며, 사용자의 홈 디렉토리 경로, 실행 파일을 찾을 수있는 디렉토리 목록 등과 같은 항목에 액세스 environ
하는 기능 (Linux의 경우 man -e 7 environ
)이 있습니다 PATH
. 쉘 스크립트도 비슷한 방식으로 모델링됩니다. 쉘 용어에는 위치 매개 변수 $1
등이 $2
있으며, $#
여러 위치 매개 변수가 있습니다. 무엇에 대해 $0
? 그것은 C 프로그램 언어에서 다시 모델링 된 실행 파일 자체의 argv[0]
이름입니다. C "실행 파일"의 이름이됩니다. 그리고 이것은 대부분의 프로그래밍 및 스크립팅 언어에있어 상당히 사실입니다 .
내가 이미 암시 한 것 중 하나는 대화식 쉘과 비 대화식 쉘 의 차이점 입니다. 명령을 입력하는 프롬프트-대화식이며 사용자와 상호 작용합니다. 반대로 쉘 스크립트가 있거나 bash -c''
비 대화식으로 실행할 때.
그리고 이것이 구별이 중요 해지는 곳입니다. 이미 실행하는 것이 쉘에 대한 위치 매개 변수 (로 양산 된 과정입니다 bash
(- "., 또는 --login 옵션으로 시작 하나 ... 그 첫 번째 문자 인수가 제로이다"로그인 쉘 하나입니다 참조 ) )
반면, 스크립트와 쉘과 시작 -c
의 장점이 걸릴 수 있습니다 옵션 $1
및 $2
인수를. 예를 들어
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
옵션의 sh
작은 단점은 일반적으로 프로그램의 이름과 달리 -c
첫 번째 위치 매개 변수를 가져 와서 할당하는 것이므로 여기에서도 사용 했습니다 $0
.
주목해야 할 또 다른 사항은 위치 매개 변수가 내가 "프레임 가능"이라고하는 것입니다. 처음에 bash
자체 위치 매개 변수로 시작했지만 이러한 위치 매개 변수가 echo
및의 매개 변수가 된 방법에 주목하십시오 stat
. 그리고 각 프로그램은 고유 한 방식으로 이해합니다. stat
문자열 을 주었고 Hello World
파일 Hello World
이 없으면 오류가 발생합니다. bash
간단한 문자열로 취급하지만 stat
해당 문자열이 기존 파일 이름이 될 것으로 예상합니다. 반대로, 모든 프로그램은 환경 변수 HOME
가 디렉토리 라는 것에 동의합니다 (프로그래머가 불합리한 방식으로 코딩하지 않는 한).
기술적으로 우리는 둘 다 엉망이지만 환경 변수를 엉망으로 만들지 말고 위치 매개 변수를 제공해야합니다. 다음과 같이 변수를 앞에 추가하여 셸에서 명령을 실행할 수 있습니다.
$ hello=world bash -c 'echo $hello'
world
export variable=value
쉘이나 스크립트 내에서 간단히 사용하여 변수를 환경에 배치 할 수도 있습니다 . 또는로 완전히 빈 환경에서 명령을 실행할 수 있습니다 env -c command arg1 arg2
. 그러나 일반적으로 환경, 특히 대문자 변수를 사용하거나 기존 환경 변수를 덮어 쓰는 것은 바람직하지 않습니다. 표준은 아니지만 권장됩니다.
위치 매개 변수의 경우 매개 변수를 설정하는 방법은 분명합니다. 명령 앞에 추가하면되지만 다른 현명 하게 설정하고shift
명령을 통해 해당 매개 변수 목록을 변경하는 방법도 있습니다 .
결론적으로이 두 가지의 목적은 다르며 이유가 있습니다. 사람들이이 답변으로부터 통찰력을 얻었기를 바랍니다.이 답변을 쓰는 것과 마찬가지로 그것을 읽는 것이 재미있었습니다.
set
명령과 같이 행동한다 설명서에 따라 (배시 교재 강조 첨가)
옵션이 없으면 각 쉘 변수 의 이름과 값이 현재 설정된 변수를 설정하거나 재설정하기위한 입력으로 재사용 할 수있는 형식으로 표시됩니다.
다시 말해 set
, 쉘과 관련된 변수를 살펴보면, 일부는 환경에 있습니다 (예 :) HOME
. 대비와 같은 명령에 의해 env
및 printenv
실제 환경 변수와 명령이 실행 봐. 참조 이 .
1="foo"
했지만 나중에 POSIX 정의에 의해 "word"(변수 또는 함수와 같은 객체의 이름)가 시작할 수 없다는 것을 알았습니다. 숫자와 함께 ( 주제에 게시 한 질문 참조 ). 위치 매개 변수는 분명히이 규칙에서 예외입니다.
$1
등을 할 수 $2
있으며 실제로는 배열이 없다는 제한을 set
피하기 위해 명령으로 수행됩니다 /bin/sh
. 관심을 가져 주셔서 감사합니다. 또한 약간의 추가 개선과 업데이트가 필요하므로 향후 며칠 동안 답변을 편집 할 것입니다.
conda
실행할 때, source conda/bin/activate
여부에 그것을 검사 $1
, $2
등, 그것은 인수 여부와 스크립트로 실행 된 여부를 결정하기 위해 설정된다. 이것은 어떤 이유로 대화 형 환경에서 설정된 시스템을 중단시킵니다. 이 비표준 동작이 대화 형 환경에서 이러한 변수를 설정하는 시스템의 결함인지 또는 스크립트로 실행되었는지 확인하기 위해 프로그램에서 사용하는 결함인지 확인하고 싶습니다.
conda
를 확인하는 ${N}
것은 확실히 잘못된 방법이므로 개발자 또는 스크립트 작성자 인 사람 에게 버그 보고서를 제출하는 것이 좋습니다 . 여기 와 여기에 같은 주제에 대한 질문이 있으며 , 다소 이식성이 좋은 방법은 ${0}
스크립트 이름과 같은지 확인하는 것 입니다. bash
실제로 그 목적에 맞는 환경 변수가 있습니다
$1, $2, $3, ..., ${10}, ${11}
변수 위치 매개 변수라고하며 떠들썩한 파티 매뉴얼 섹션에서 다루는3.4.1
3.4.1 위치 매개 변수
위치 매개 변수는 단일 숫자 0 이외의 하나 이상의 숫자로 표시되는 매개 변수입니다. 위치 매개 변수는 호출 될 때 쉘의 인수에서 지정되며 set builtin 명령을 사용하여 다시 지정할 수 있습니다. 위치 매개 변수 N은 $ {N} 또는 N이 한 자리로 구성되는 경우 $ N으로 참조 될 수 있습니다. 할당 문에는 위치 매개 변수를 할당 할 수 없습니다. set 및 shift 내장은 설정 및 설정 해제에 사용됩니다 (Shell 내장 명령 참조). 쉘 기능이 실행될 때 위치 매개 변수가 일시적으로 대체됩니다 (쉘 기능 참조).
두 자리 이상의 숫자로 구성된 위치 매개 변수가 확장되면 중괄호로 묶어야합니다.
에 관해서 $?
와 $0
,이 특별한 매개 변수는 바로 다음 섹션에 설명되어 있습니다3.4.2
3.4.2 특수 매개 변수
쉘은 여러 매개 변수를 특별히 처리합니다. 이 매개 변수는 참조 만 가능합니다. 그들에게 할당은 허용되지 않습니다.
...
?
($?) 가장 최근에 실행 된 포 그라운드 파이프 라인의 종료 상태로 확장됩니다.
0
($ 0) 쉘 또는 쉘 스크립트 이름으로 확장합니다. 이것은 셸 초기화시 설정됩니다. 명령 파일 (Bash 스크립트 참조)로 Bash를 호출하면 $ 0이 해당 파일 이름으로 설정됩니다. Bash가 -c 옵션으로 시작되면 (Bash 호출 참조) $ 0은 실행될 문자열 뒤의 첫 번째 인수 (있는 경우)로 설정됩니다. 그렇지 않으면 인수 0으로 지정된대로 Bash를 호출하는 데 사용 된 파일 이름으로 설정됩니다.
$1
, $2
... 위치 매개 변수이며, 환경 변수는 물론 변수가 아닙니다.
본쉘 같은 용어에서 $something
라고 매개 변수 확장 (또한 커버 ${something#pattern}
등과 같은 몇 가지 껍질에 ${array[x]}
, ${param:offset}
, ${x:|y}
그리고 더 많은 확장 사업자).
여러 종류의 매개 변수가 있습니다.
$foo
,$PATH
$1
, $2
... 스크립트가 수신 한 인수)$0
, $-
, $#
, $*
, $@
, $$
, $!
, $?
...Bourne의 쉘과 같은 변수 이름은 하나의 알파벳 문자 (로케일에 의해 인식되거나 쉘에 따라 a-zA-Z로 제한됨)와 밑줄로 시작하고 0 개 이상의 영숫자 문자 또는 밑줄로 시작해야합니다.
쉘에 따라 변수는 다른 유형 (스칼라, 배열, 해시)을 갖거나 특정 속성 (읽기 전용, 내 보낸, 소문자 ...)을 가질 수 있습니다.
이러한 변수 중 일부는 쉘에 의해 생성되거나 쉘에 특별한 의미를 갖습니다 (예 $OPTIND
: $IFS
,, $_
...)
내보내기 속성이 있는 쉘 변수는 환경 변수 로 쉘이 실행하는 명령에 자동으로 내보내집니다 .
환경 변수는 쉘 변수와 분리 된 개념입니다. 환경 변수를 명령 실행에 전달하는 유일한 방법은 쉘 변수를 내보내는 것이 아닙니다.
VAR=foo
export VAR
printenv VAR
VAR
환경 변수를 printenv
명령에 전달합니다 (내용을 인쇄하도록 지시합니다).
env VAR=foo printenv VAR
또는:
perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'
예를 들어.
환경 변수는 임의의 이름을 가질 수 있습니다 (모든 문자를 포함 =
할 수 있지만 비어있을 수도 있음). Bourne과 같은 쉘 변수 이름과 호환되지 않는 이름을 환경 변수에 제공하는 것은 좋지 않지만 가능합니다.
$ env '#+%=whatever' printenv '#+%'
whatever
쉘은 이름이 유효한 쉘 변수 인 환경 변수에 대해서만 수신 한 환경 변수 를 쉘 변수에 맵핑합니다 (일부 쉘에서는와 같은 일부 특수 변수는 무시합니다 $IFS
).
따라서 1
환경 변수를 명령 에 전달할 수는 있지만
$ env '1=whatever' printenv 1
whatever
그렇다고 해당 환경 변수로 쉘을 호출하면 $1
매개 변수 의 값이 설정된다는 의미는 아닙니다 .
$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo
아니요, 스크립트의 매개 변수입니다. 예를 들어 다음과 같이 스크립트를 호출하면
mynicescript.sh one two three
그런 다음 스크립트 내부에서 이러한 매개 변수를 사용할 수 있습니다
$1 = one
$2 = two
$3 = three
$ 0는 스크립트 자체의 이름입니다.
따라서 스크립트 외부에 있으면 이러한 변수를 사용할 수 없습니다 ($ 0 제외, / bin / bash-셸 자체).
$0
현재 터미널 프로세스 (bash와 유사)를 가리키며 $?
단순히 마지막 프로세스의 종료 코드입니다.
gnome-terminal
with 인수 ( gnome-terminal Hello World
) 를 실행하려고했습니다 . 나는 볼 수 있었다 $0
, 그러나 나는 볼 수 없었다 $1
및 $2
.
export 3
로 전환 할 수 없습니다$3
. 당신은 할 수 없습니다unset 3
; 를$3
사용하여 새 값을 할당 할 수 없습니다3=val
.