동일한 이름을 가진 쉘 함수 및 변수

동일한 이름을 가진 쉘 함수 및 변수

~에서배쉬 매뉴얼:

동일한 이름을 가진 쉘 함수 및 변수는 쉘 하위 항목에 전달되는 동일한 이름을 가진 환경에 여러 항목이 생성될 수 있습니다. 이로 인해 문제가 발생할 수 있으니 주의하세요.

bash는 "쉘 함수와 동일한 이름을 가진 변수"를 어떻게 구별합니까?

$  func () { return 3; }; func=4; declare -p func; declare -f func;
declare -- func="4"
func () 
{ 
  return 3
}

"환경에서 동일한 이름을 가진 여러 항목이 쉘의 하위 항목으로 전달"되는 경우는 언제입니까?

문제가 발생할 때 무엇에 "주의"해야 합니까?

답변1

전반적인 상황: 독립적인 네임스페이스

일반적으로 쉘은 변수와 함수가 서로 다른 컨텍스트에서 사용되기 때문에 이를 구별합니다. 간단히 말해서 이름은 a 뒤에 나타나 $거나 내장 함수에 대한 인수로 나타나는 경우(예: export(without -f) 및 unset(without )) 변수 이름입니다. -f이름은 명령(별명 확장 후 ) 또는 인수 등으로 나타나는 경우 함수 export -f이름 입니다.unset -f

변수를 환경으로 내보낼 수 있습니다. 환경 변수는 셸 변수와 동일한 이름(및 동일한 값)을 갖습니다.

이전 bash의 경우: 함수 내보내기로 인한 혼란

대부분의 다른 셸과 달리 Bash는 기능을 환경으로 내보낼 수도 있습니다. 환경에는 유형 표시가 없기 때문에 환경의 항목이 환경 변수의 이름이나 값을 분석하는 것 외에는 기능인지 여부를 식별할 수 있는 방법이 없습니다.

이전 버전의 bash는 함수 이름을 이름으로 사용하고 함수 정의와 비슷한 것을 함수 값으로 사용하여 환경에 함수를 저장했습니다. 예를 들어:

bash-4.1$ foobar () { echo foobar; }
bash-4.1$ export -f foobar
bash-4.1$ env |grep -A1 foobar
foobar=() {  echo foobar
}
bash-4.1$ 

{ echo foobar; }코드가 다음과 같은 함수 와 값이 다음과 같은 변수 () { echo foobar␤}(여기서는 개행 문자임) 사이에는 차이가 없습니다 . 이는 잘못된 디자인 결정으로 판명되었습니다.

때로는 잠재적으로 적대적인 개체에 의해 값이 제어되는 환경 변수를 사용하여 쉘 스크립트가 호출됩니다. 예를 들어 CGI 스크립트입니다. Bash의 함수 내보내기/가져오기 기능을 사용하면 이러한 방식으로 함수를 주입할 수 있습니다. 예를 들어 스크립트를 실행합니다.

#!/bin/bash
ls

환경에 특정 이름(예: )을 가진 변수가 포함되지 않는 한 PATH원격 요청의 요청은 안전합니다 . 그러나 요청이 환경 변수를 ls로 설정할 수 있다면 그것이 함수의 본문이므로 () { cat /etc/passwd; }bash는 이를 기꺼이 실행할 것입니다 .cat /etc/passwdls

최신 bash 사용: 훨씬 덜 혼란스럽습니다.

이 보안 취약점은 다음으로 인해 발생합니다.스티븐 차제라스한 측면으로쉘 쇼크 버그. Shellshock 이후 버전의 bash에서 내보낸 함수는 다음으로 식별됩니다.이름내용보다는.

bash-4.3$ foobar () { echo foobar; }
bash-4.3$ export -f foobar
bash-4.3$ env |grep -A1 foobar
BASH_FUNC_foobar%%=() {  echo foobar
}

BASH_FUNC_foobar%%유사한 이름은 일반적으로 명령 이름으로 사용되지 않으며 환경 변수 전달을 허용하는 인터페이스를 통해 필터링할 수 있으므로 보안 문제는 없습니다 . 기술적으로 %환경 변수 이름에 문자를 포함하는 것이 가능합니다(이것이 현대 bash의 내보낸 함수가 작동하는 이유입니다). 그러나 일반적으로 쉘은 %변수 이름을 허용하지 않기 때문에 사람들은 그렇게 하지 않습니다.

bash 매뉴얼의 이 문장은 이전(Shellshock 이전) 동작을 나타냅니다. 업데이트하거나 삭제해야 합니다. 최신 bash 버전의 경우 환경 변수 이름이 %%.

답변2

Emacs Lisp에서도 비슷한 상황이 발생합니다. 여기에는 두 개의 네임스페이스가 있는데, 하나는 함수용이고 다른 하나는 변수용입니다. (var)함수 컨텍스트()에서 기호를 역참조하면 함수가 호출되고, 변수 컨텍스트( 예 var: 괄호 없이)에서 기호를 역참조하면 변수가 제공됩니다. 예를 들어:

(defun myvar (myvar)
  "adds 3 to MYVAR"
  (+ 3 myvar))
(setq myvar 7)
(message (myvar myvar))

실행됩니다기능 myvar매개변수는 7변수의 역참조입니다 myvar.

익숙하지 않으면 매우 혼란스러울 수 있습니다.

문제를 검토하고 테스트한 후세게 때리다동일한 동작을 보이는 것에 놀랐습니다. 위의 ELisp를 bash로 변환합니다.

[grochmal@phoenix ~]$ myvar () { echo $(($1+3)); }
[grochmal@phoenix ~]$ myvar=7
[grochmal@phoenix ~]$ myvar $myvar
10

$이 점에서 Bash는 변수에 레이블을 지정 해야 하기 때문에 ELisp보다 더 혼란스럽습니다 . 그래도 이 이름은 declare두 가지를 포괄하는 이름처럼 보일 수도 있습니다. 바라보다:

[grochmal@phoenix ~]$ declare -p myvar
declare -x myvar="7"
[grochmal@phoenix ~]$ declare -f myvar
myvar () 
{ 
    echo $(($1+3))
}

(PS 일단 두 개의 네임스페이스의 존재에 익숙해지면, 예를 들어 한동안 ELisp에서 프로그래밍을 했다면 더 이상 혼란스럽지 않습니다.)

관련 정보