source

셸 스크립트가 호출 셸의 환경 변수를 설정할 수 있습니까?

ittop 2023. 5. 17. 23:27
반응형

셸 스크립트가 호출 셸의 환경 변수를 설정할 수 있습니까?

실행 시 호출자의 셸에 설정된 환경 변수를 설정하는 셸 스크립트를 작성하려고 합니다.

setenv FOO foo

csh/tcsh 단위, 또는

export FOO=foo

insh/ssh는 스크립트 실행 중에만 설정합니다.

나는 이미 그것을 알고 있다.

source myscript

에서는 새 셸을 시작하는 대신 스크립트 명령을 실행하므로 "사용자" 환경이 설정될 수 있습니다.

하지만 여기에 문제가 있습니다.

나는 이 스크립트를 bash 또는 csh에서 호출할 수 있기를 원합니다.즉, 두 셸 중 하나의 사용자가 내 스크립트를 실행하고 셸의 환경을 변경할 수 있기를 원합니다.따라서 csh를 실행하는 사용자는 bash 스크립트를 소스할 수 없고 bash를 실행하는 사용자는 acsh 스크립트를 소스할 수 없기 때문에 'source'는 나에게 작동하지 않습니다.

스크립트에 두 가지 버전을 작성하고 유지 관리할 필요가 없는 합리적인 솔루션이 있습니까?

점 공간 스크립트 호출 구문을 사용합니다.예를 들어 스크립트의 전체 경로를 사용하여 이 작업을 수행하는 방법은 다음과 같습니다.

. /path/to/set_env_vars.sh

스크립트와 동일한 디렉토리에 있는 경우 다음과 같은 방법이 있습니다.

. set_env_vars.sh

셸 합니다../set_env_vars.sh시할 수 있습니다.). 동일한 셸에서 실행되므로 종료 시 설정한 환경 변수를 사용할 수 있습니다.

이것은 전화하는 것과 같습니다.source set_env_vars.sh하지만 타이핑하는 것이 더 짧고 일부 장소에서 작동할 수 있습니다.source안 합니다.

셸 프로세스에는 상위 프로세스의 환경 복사본이 있고 상위 프로세스의 환경에 대한 액세스 권한이 없습니다.셸 프로세스가 종료되면 해당 환경에 대한 변경 내용이 손실됩니다.셸 환경을 구성하는 데 가장 일반적으로 사용되는 방법은 스크립트 파일을 소싱하는 것입니다. 두 가지 셸 유형 각각에 대해 하나씩 유지하는 것이 좋습니다.

호출자의 셸은 프로세스 컨텍스트가 다르기 때문에 수정할 수 없습니다.하위 프로세스가 셸의 변수를 상속할 때는 복사본 자체를 상속하는 것입니다.

한 가지 방법은 tcsh 또는 sh에 대한 올바른 명령을 실행하는 스크립트를 작성하는 것입니다.스크립트가 "설정"인 경우 다음을 수행합니다.

ln -s setit setit-sh

그리고.

ln -s setit setit-csh

이제 직접 또는 별칭으로 sh에서 이 작업을 수행합니다.

eval `setit-sh`

아니면 이것은 csh에서.

eval `setit-csh`

set it는 출력 스타일을 결정하기 위해 $0을 설정합니다.

이것은 사람들이 TERM 환경 변수 세트를 얻기 위해 사용하는 방법을 상기시킵니다.

여기서의 장점은 원하는 셸에 다음과 같이 기록된다는 것입니다.

#!/bin/bash
arg0=$0
arg0=${arg0##*/}
for nv in \
   NAME1=VALUE1 \
   NAME2=VALUE2
do
   if [ x$arg0 = xsetit-sh ]; then
      echo 'export '$nv' ;'
   elif [ x$arg0 = xsetit-csh ]; then
      echo 'setenv '${nv%%=*}' '${nv##*=}' ;'
   fi
done

위에 주어진 심볼릭 링크와 뒤에 인용된 표현식의 평가를 사용하면 원하는 결과를 얻을 수 있습니다.

csh, tcsh 또는 유사한 셸에 대한 호출을 단순화하려면:

alias dosetit 'eval `setit-csh`'

또는 sh, bash 등의 경우:

alias dosetit='eval `setit-sh`'

한 가지 좋은 점은 목록을 한 곳에서만 관리하면 된다는 것입니다.이론적으로 당신은 심지어 목록을 파일에 넣고 넣을 수도 있습니다.cat nvpairfilename 사이에 .

이것은 로그인 셸 터미널 설정이 수행되던 방식입니다. 스크립트는 로그인 셸에서 실행될 문을 출력합니다.별칭은 일반적으로 "tset vt100"에서와 같이 호출을 단순하게 만드는 데 사용됩니다.다른 답변에서 언급했듯이, INN UseNet 뉴스 서버에도 유사한 기능이 있습니다.

.bash_profile에 다음과 같은 정보가 있습니다.

# No Proxy
function noproxy
{
    /usr/local/sbin/noproxy  #turn off proxy server
    unset http_proxy HTTP_PROXY https_proxy HTTPs_PROXY
}


# Proxy
function setproxy
{
    sh /usr/local/sbin/proxyon  #turn on proxy server 
    http_proxy=http://127.0.0.1:8118/
    HTTP_PROXY=$http_proxy
    https_proxy=$http_proxy
    HTTPS_PROXY=$https_proxy
    export http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
}

따라서 프록시를 비활성화하려면 로그인 셸에서 함수가 실행되고 변수를 예상대로 설정합니다.

gdb와 setenv(3)를 사용하면 "어느 정도" 가능하지만 실제로 이것을 하는 것을 추천하는 데 어려움이 있습니다. (게다가, 가장 최근의 우분투는 실제로 커널에게 ptrace에 대해 더 관대해지라고 말하지 않고는 이를 수행할 수 없으며, 다른 디스트리뷰터들에게도 마찬가지일 수 있습니다.)

$ cat setfoo
#! /bin/bash

gdb /proc/${PPID}/exe ${PPID} <<END >/dev/null
call setenv("foo", "bar", 0)
END
$ echo $foo

$ ./setfoo
$ echo $foo
bar

이것은 효과가 있습니다. 제가 사용하는 것은 아니지만 '효과'가 있습니다.teredo 변수를 합니다.TEREDO_WORMS:

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i

이는 Korn 쉘에 의해 해석되고 환경 변수를 내보낸 다음 새로운 대화형 쉘로 대체됩니다.

스크립트를 에 이스트실전우에는리기를행하립크가 있습니다.SHELLC 쉘및 변수 환서 C 정설로, 고환경변수TEREDO_WORMS설정되지 않음:

% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%

스크립트가 실행되면 다른 대화형 C 셸인 새 셸에 있지만 환경 변수는 다음과 같이 설정됩니다.

% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

이 셸을 종료하면 원래 셸이 다음 작업을 수행합니다.

% exit
% env | grep TEREDO
%

환경 변수가 원래 셸의 환경에서 설정되지 않았습니다.사용하는 경우exec teredo명령을 실행하려면 원래 대화형 셸이 환경을 설정하는 Korn 셸로 대체되고 다음과 같이 새로운 대화형 C 셸로 대체됩니다.

% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

는 경우력을 하면.exit(또는 ), 셸이 종료되면 해당 창에서 로그아웃하거나 실험이 시작된 이전 수준의 셸로 돌아갑니다.

동일한 메커니즘이 Bash 또는 Korn 셸에서 작동합니다.종료 명령 뒤에 나타나는 프롬프트가 재미있는 곳에 나타날 수 있습니다.


설명에 토론을 기록합니다. 모든과 함께 인 목적을 합니다.-i대화형 셸을 만드는 옵션).추할수있다니습을 추가할 수도 ."$@"다른 인수를 릴레이하는 옵션 뒤에 셸을 일반적인 '환경 설정 및 명령 실행' 도구로 사용할 수 있습니다.를 생략하는 것이 좋을 수도 있습니다.-i다른 인수가 있는 경우 다음과 같은 결과를 초래됩니다.

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-'-i'}"

"${@-'-i'}"인수가 포함되어 목록을 않으면 ' 비인 ' 목는 ' 하이인 ' 트의를 ' 수어있 ' 포수고 '로 합니다.-i존재하지 않는 인수'에 대해 설명합니다.

모듈을 사용해야 합니다. http://modules.sourceforge.net/ 을 참조하십시오.

편집: 모듈 패키지는 2012년 이후 업데이트되지 않았지만 기본적인 사항은 여전히 정상적으로 작동합니다.모든 새로운 기능, 벨 및 휘파람은 오늘날 lmod에서 발생합니다(저는 그것을 더 좋아합니다): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod

언급되지 않은 또 다른 해결 방법은 변수 값을 파일에 쓰는 것입니다.

저는 모든 테스트 대신 마지막 세트 테스트를 실행하고 싶은 매우 유사한 문제에 부딪혔습니다.저의 첫 번째 계획은 환경 변수 TESTCASE를 설정하기 위한 명령을 작성한 다음 이를 사용하여 테스트를 실행하는 다른 명령을 작성하는 것이었습니다.말할 필요도 없이 저도 당신과 똑같은 문제를 가지고 있었습니다.

하지만 저는 이 간단한 해킹을 생각해냈습니다.

번째 명령어 ( 첫번째명령(령명▁(()testset):

#!/bin/bash

if [ $# -eq 1 ]
then
  echo $1 > ~/.TESTCASE
  echo "TESTCASE has been set to: $1"
else
  echo "Come again?"
fi

번째 명령두번째명령명(령▁(()testrun):

#!/bin/bash

TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE

하위 프로세스에 환경 변수를 인쇄하도록 지시한 다음("env" 호출) 상위 프로세스에서 인쇄된 환경 변수를 루프하고 해당 변수에 대해 "내보내기"를 호출할 수 있습니다.

다음 코드는 find . -print0의 출력을 bash 어레이에 캡처하는 것을 기반으로 합니다.

상위 셸이 bash인 경우 다음을 사용할 수 있습니다.

while IFS= read -r -d $'\0' line; do
    export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME

에는 상셸대인경우시이위▁if▁then경우대인.read는 더욱 .

TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
    export VARNAME=something
    while IFS= read -r -d $'\0' line; do
        echo $(printf '%q' "$line")
    done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME

X 작업을 할 수 있습니다.
파일을 생성하여 변수 을 해제합니다. 설정을 해제합니다.

#!/bin/bash
unset http_proxy

파일을 실행 파일로 만들기

sudo chmod 744 unsetvar

별칭 만들기

alias unsetvar='source /your/path/to/the/script/unsetvar'

스크립트 파일이 들어 있는 폴더가 경로에 추가되어 있으면 오래 사용할 수 있습니다.

이것은 제가 탁월하다고 부르는 것은 아니지만, 어쨌든 셸에서 스크립트를 호출해야 하는 경우에도 작동합니다.좋은 솔루션은 아니지만, 단일 정적 환경 변수에 대해서는 충분히 잘 작동합니다.

1.) 0(성공) 또는 1(성공하지 못함)을 종료하는 조건으로 스크립트 생성

if [[ $foo == "True" ]]; then
    exit 0
else
    exit 1

2.) 종료 코드에 종속된 별칭을 만듭니다.

alias='myscript.sh && export MyVariable'

부모 셸에서 환경 변수를 설정하기 위해 '&&'을 통해 0을 종료해야 하는 조건을 평가하는 스크립트를 호출하는 별칭을 호출합니다.

이것은 플롯삼이지만, 꼬집었을 때 유용할 수 있습니다.

다른 bash_profile을 사용하여 다른 Bash를 호출할 수 있습니다.또한 다중 bashprofile 환경에서 사용할 특수 bash_profile을 생성할 수 있습니다.

bashprofile 내부의 함수를 사용할 수 있으며 이 함수는 글로벌하게 사용할 수 있습니다.예를 들어 "function user {export USER_NAME $1}"은 런타임에 변수를 설정할 수 있습니다. 예: user olegchir & & env | grepolegchir

또 다른 방법은 "환경 모듈"(http://modules.sourceforge.net/) )을 사용하는 것입니다.이것은 불행하게도 혼합물에 제3의 언어를 도입합니다.사용자는 Tcl 언어로 환경을 정의하지만 일반적인 수정을 위한 몇 가지 유용한 명령이 있습니다(예시 대 추가 대 집합이 있습니다.또한 환경 모듈을 설치해야 합니다.그러면 다음을 사용할 수 있습니다.module load *XXX*원하는 환경의 이름을 지정합니다.으로 모듈명기다고별다니칭입급음의의 입니다.eval위에서 토마스 캠마이어에 의해 설명된 메커니즘.여기서 가장 큰 장점은 환경을 한 언어로 유지하고 "환경 모듈"에 의존하여 sh, ksh, bash, csh, tcsh, zsh, python(!?!!) 등으로 변환할 수 있다는 것입니다.

파이프, 평가 및 신호를 사용하여 솔루션을 만들었습니다.

parent() {
    if [ -z "$G_EVAL_FD" ]; then
            die 1 "Rode primeiro parent_setup no processo pai"
    fi
    if [ $(ppid) = "$$" ]; then
            "$@"
    else
            kill -SIGUSR1 $$
            echo "$@">&$G_EVAL_FD
    fi
}
parent_setup() {
    G_EVAL_FD=99
    tempfile=$(mktemp -u)
    mkfifo "$tempfile"
    eval "exec $G_EVAL_FD<>'$tempfile'"
    rm -f "$tempfile"
    trap "read CMD <&$G_EVAL_FD; eval \"\$CMD\"" USR1
}
parent_setup #on parent shell context
( A=1 ); echo $A # prints nothing
( parent A=1 ); echo $A # prints 1

어떤 명령으로도 작동할 수 있습니다.

협력 프로세스를 통해 이 문제를 해결하는 방법을 문서화한 답변이 없습니다.▁pattern와 같은 것들과 인 패턴.ssh-agent가 할 수 있는 입니다.eval.

bash$ eval $(shh-agent)

를 들면, 들면를예,ssh-agent에는 Csh 또는 Bourne 호환 출력 구문을 선택할 수 있는 옵션이 있습니다.

bash$ ssh-agent
SSH2_AUTH_SOCK=/tmp/ssh-era/ssh2-10690-agent; export SSH2_AUTH_SOCK;
SSH2_AGENT_PID=10691; export SSH2_AGENT_PID;
echo Agent pid 10691;

이렇게 하면 에이전트가 실행되기 시작하지만 셸 프롬프트에 이 출력을 복사하여 붙여넣지 않는 한 실제로 사용할 수 없습니다.비교:

bash$ ssh-agent -c
setenv SSH2_AUTH_SOCK /tmp/ssh-era/ssh2-10751-agent;
setenv SSH2_AGENT_PID 10752;
echo Agent pid 10752;

, (보시피다,피보)csh그리고.tcsh사용하다setenv변수를 설정합니다.)

여러분 자신의 프로그램도 이것을 할 수 있습니다.

bash$ foo=$(makefoo)

당신의.makefoo스크립트는 단순히 값을 계산하고 인쇄한 다음 호출자가 원하는 것을 무엇이든 할 수 있도록 합니다. 변수에 할당하는 것은 일반적인 사용 사례이지만, 값을 생성하는 도구에 하드 코딩하고 싶은 것은 아닐 수도 있습니다.

엄밀히 말하면, 그것은 맞습니다. 오직 'eval'만이 다른 껍질을 포크하지 않습니다.그러나 수정된 환경에서 실행하려는 응용 프로그램의 관점에서는 차이가 없습니다. 즉, 자식이 부모의 환경을 상속하므로 (수정된) 환경이 모든 내림차순 프로세스로 전달됩니다.

따라서 상위 프로그램/셸에서 실행되는 한 변경된 환경 변수 'sticks'도 마찬가지입니다.

부모(Perlor shell)가 종료된 후에도 환경 변수가 남아 있어야 하는 경우 부모 셸이 무거운 리프팅을 수행해야 합니다.문서에서 본 한 가지 방법은 현재 스크립트가 필요한 '내보내기' 언어로 실행 파일을 생성하는 것입니다.그런 다음 수정된 환경의 비휘발성 버전을 남겨두려면 명령 앞에 'source'를 붙여야 한다는 사실을 항상 인식하면서 상위 셸을 속여서 실행합니다.기껏해야 클루지.

두 번째 방법은 셸 환경(.bashrc 등)을 시작하는 스크립트를 수정하여 수정된 매개 변수를 포함하는 것입니다.이것은 위험할 수 있습니다. 초기화 스크립트를 호스로 연결하면 다음 번에 시작하려고 할 때 셸을 사용할 수 없게 될 수 있습니다.현재 셸을 수정할 수 있는 도구가 많이 있습니다. '런처'에 필요한 조정을 추가하면 이러한 변경 사항도 효과적으로 추진할 수 있습니다.일반적으로 좋은 생각은 아닙니다. 특정 애플리케이션 제품군에 대한 환경 변경만 필요한 경우 나중에 셸 시작 스크립트를 원래 상태(vi 또는 기타를 사용)로 되돌려야 합니다.

간단히 말해서, 좋은 (그리고 쉬운) 방법은 없습니다.아마도 이것은 시스템의 보안이 돌이킬 수 없을 정도로 손상되지 않도록 보장하기 어렵게 되었습니다.

간단히 말하면, 상위 프로세스의 환경을 변경할 수는 없지만 사용자가 선택한 사용자 지정 환경 변수와 셸이 있는 환경을 원하는 것 같습니다.

그래서 왜 단순히 그런 것이 아닙니다.

#!/usr/bin/env bash
FOO=foo $SHELL

그러면 환경을 다 처리한 후에exit.

항상 별칭을 사용할 수 있습니다.

alias your_env='source ~/scripts/your_env.sh'

저는 이것을 수년 전에 했습니다..bashrc 및 .cshrc 각각에 별칭을 포함하고 매개 변수를 사용하여 환경을 공통 형식으로 설정하는 각 형식을 별칭으로 지정했습니다.

그런 다음 두 개의 셸 중 하나에서 소스할 스크립트에는 각 셸에 앨리어싱된 적절한 마지막 형식의 명령이 있습니다.

구체적인 가명을 찾으면 게시하겠습니다.

$SHELL/$TERM이 설정된 값에 따라 조건부 쓰기를 제외하고는 아니요.Perl을 사용하는 데 문제가 있습니까?그것은 어디에나 있고(그것이 없는 UNIX 변형은 생각할 수 없습니다), 그리고 그것은 당신의 수고를 덜어줄 것입니다.

언급URL : https://stackoverflow.com/questions/496702/can-a-shell-script-set-environment-variables-of-the-calling-shell

반응형