변수의 값을 잃지 않고 변수를 내 보내지 않으려면 어떻게해야합니까?


10

변수를 내 보냈다고 가정 해 봅시다.

foo=bar
export foo

이제 내보내기를 해제하고 싶습니다. 즉, sh -c 'echo "$foo"'내가하면 안된다 bar. 의 환경에 전혀 foo표시되지 않아야 sh -c합니다. sh -c변수의 존재를 보여주는 쉬운 방법 일뿐입니다. 명령은 무엇이든 될 수 있습니다-환경에 변수의 존재로 인해 단순히 행동에 영향을 미치는 것일 수 있습니다.

제가 할수 있어요:

  1. unset 변수를 잃고
  2. env각 명령을 사용하여 제거하십시오 .env -u foo sh -c 'echo "$foo"'
    • 잠시 동안 현재 셸을 계속 사용하려는 경우 비실용적입니다.

이상적으로는 변수의 값을 유지하고 싶지만 빈 변수가 아닌 자식 프로세스에 전혀 표시되지 않아야합니다.

내가 할 수있는 것 같아요 :

otherfoo="$foo"; unset foo; foo="$otherfoo"; unset otherfoo

otherfoo이미 존재하는 경우 넘어 질 위험이 있습니다.

그게 유일한 방법인가요? 표준 방법이 있습니까?


1
다음을 사용하여, 임시 파일에 값을 에코 할 수 mktemp있다면 소스를 변수를 할당하는 임시 파일을 휴대용 정도이며, 값 설정을 해제합니다. 쉘 변수와 달리 임의의 이름으로 임시 파일을 만들 수 있습니다.
Thomas Dickey

@Sukminder이 sh -c명령은 단지 예일 뿐입니다. 원하는 경우 변수를 설정 해제 할 수없는 명령을 수행하십시오.
muru

답변:


6

표준적인 방법은 없습니다.

함수를 사용하여 임시 변수를 사용하지 않아도됩니다. 다음 함수는 설정 해제 된 변수를 설정 해제하고 비어있는 변수를 비워 두도록 관리합니다. 그러나 읽기 전용 또는 유형 변수와 같은 일부 쉘에서 발견되는 기능은 지원하지 않습니다.

unexport () {
  while [ "$#" -ne 0 ]; do
    eval "set -- \"\${$1}\" \"\${$1+set}\" \"\$@\""
    if [ -n "$2" ]; then
      unset "$3"
      eval "$3=\$1"
    fi
    shift; shift; shift
  done
}
unexport foo bar

ksh, bash 및 zsh에서을 사용하여 변수를 내보내기 할 수 없습니다 typeset +x foo. 이렇게하면 유형과 같은 특수 속성이 유지되므로 사용하는 것이 좋습니다. 나는 typeset내장 된 모든 껍질이 있다고 생각합니다 typeset +x.

case $(LC_ALL=C type typeset 2>&1) in
  typeset\ *\ builtin) unexport () { typeset +x -- "$@"; };;
  *) unexport () {  };; # code above
esac

1
에 익숙하지 않은 사용자의 경우 비어 있더라도 설정 ${var+foo}되어 foo있는지 , 그렇지 않은 경우 평가됩니다 var.
muru

말은, 당신이 의견이 어떻게 typeset +xexport -n이전을 지원하지 껍질을 검색 하시나요? 가 export -n희소, 또는 일부 속성을 보존하지 않는 이유는 무엇입니까?
muru

@muru bash 스크립트를 작성하는 경우 무관심하게 사용 export -n하거나 사용할 수 있습니다 typeset +x. ksh 또는 zsh에는 만 typeset +x있습니다.
Gilles 'SO- 악의를 멈추십시오'

7

편집 : 의 경우 bash만 의견에서 지적했듯이 :

-n에 옵션 export제거 export각각의 주어진 이름의 속성입니다. (참조 help export)

그래서 위해 bash, 당신이 원하는 명령은 다음과 같습니다export -n foo


1
그것은 쉘에 특정 적 이며 ( POSIX 참조 ) OP는 쉘을 지정하지 않았지만 문제를 해결 하는 표준 방법을 요구했습니다 .
Thomas Dickey

1
@ThomasDickey는 그 사실을 몰랐습니다. 감사합니다.
와일드 카드

3

비슷한 POSIX 함수를 작성했지만 임의의 코드 실행 위험이 없습니다.

unexport()
    while case ${1##[0-9]*} in                   ### rule out leading numerics
          (*[!_[:alnum:]]*|"")                   ### filter out bad|empty names
          set "" ${1+"bad name: '$1'"}           ### prep bad name error
          return ${2+${1:?"$2"}}                 ### fail w/ above err or return 
          esac
    do    eval  set '"$'"{$1+$1}"'" "$'"$1"'" "$'@\" ###  $1 = (  $1+ ? $1 : "" )
          eval  "${1:+unset $1;$1=\$2;} shift 3"     ### $$1 = ( $1:+ ? $2 : -- )
    done

또한 당신이 제공하고자하는만큼 많은 주장을 다룰 것입니다. 인수가 아직 설정되지 않은 유효한 이름이면 자동으로 무시됩니다. 인수가 잘못된 이름이면 stderr에 쓰고 적절하게 중지되지만 명령 행에서 유효하지 않은 선행 이름은 계속 처리됩니다.

다른 방법을 생각했습니다. 나는 그것을 더 좋아합니다.

unexport()
        while   unset OPTARG; OPTIND=1           ### always work w/ $1
                case  ${1##[0-9]*}    in         ### same old same old
                (*[!_[:alnum:]]*|"")             ### goodname && $# > 0 || break
                    ${1+"getopts"} : "$1"        ### $# ? getopts : ":"
                    return                       ### getopts errored or ":" didnt
                esac
        do      eval   getopts :s: '"$1" -"${'"$1+s}-\$$1\""
                eval   unset  "$1;  ${OPTARG+$1=\${OPTARG}#-}"
                shift
        done

둘 다 같은 기술을 많이 사용합니다. 기본적으로 쉘 var가 설정되어 있지 않으면 그것에 대한 참조는 +매개 변수 확장으로 확장 되지 않습니다 . 그러나 값에 관계없이 설정 되면 변수의 값이 아닌 다음과 같이 매개 변수 ${parameter+word}가 확장됩니다 word. 따라서 쉘 변수는 성공시 자체 테스트 및 자체 대체 변수입니다.

또한 스스로 실패 할 수도 있습니다 . 나쁜 이름을 움직일 발견되면 정상 기능에 $1$2와 휴가 $1내가 할 다음 일은 중 하나이기 때문에 널 return인수가 무효 인 경우, 쉘 것, 모든 인수가 처리 된 경우 성공은 루프 끝에서, 또는 확장 $2$1:?이는 스크립트 쉘을 죽이고 쓰는 동안 대화 형 하나에 인터럽트를 반환합니다 wordstderr로.

두 번째 getopts는 과제를 수행합니다. 그리고 나쁜 이름을 할당하지 않습니다-오히려 표준 오류 메시지를 stderr에 작성합니다. 또한 인수가 처음에 설정된 변수의 이름 인 $OPTARG 경우 arg의 값을 저장합니다 . 따라서 getopts필요한 모든 작업을 수행 한 후 적절한 할당으로 eval세트를 OPTARG확장해야합니다.


2
요즘, 나는 당신의 대답 중 하나에 머리를 감 으려고 노력한 후 어딘가 정신과 병동에있을 것입니다. : D 다른 답변은 임의의 코드 실행으로 어떻게 고통 받습니까? 예를 들어 줄 수 있습니까?
muru

3
@muru-인수가 유효하지 않은 이름이 아닌 한 아닙니다. 그러나 그것은 문제가 아닙니다-문제는 입력이 검증되지 않았다는 것입니다. 예, 임의의 코드를 실행하려면 이상한 이름의 인수를 전달해야합니다. 그러나 이는 역사상 모든 CVE의 근간이됩니다. export이상한 이름 을 시도해도 컴퓨터를 죽이지 않습니다.
mikeserv

1
@muru-아, 그리고 인수는 임의적 일 수 있습니다 : var=something; varname=var; export "$varname"완벽하게 유효합니다. 똑같이 간다. unset이것과 다른 것들도 마찬가지 이지만, 그 "$varname"변수 의 내용 이 미쳤을 때, 후회 할 수있다. 이것이 바로 전체 bash함수 내보내기 디 버클이 어쨌든 일어났던 방식입니다.
mikeserv

1
@mikeserv 난독 화 된 코드를 스스로 설명하는 코드로 바꾸거나 (적어도 주석을 달았습니다)
PSkocik

1
@PSkocik-완료
mikeserv 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.