쉘 프로파일 및 현재 디렉토리 후크를 사용하여 쉘 명령을 실행하는 방법 (예 : direnv)


9

나는 얻기 위해 노력하고 있어요 shell-commandasync-shell-command내에서 프로그램의 부부와 함께 완벽하게 통합되도록 .bashrc특별히, 파일 direnv 이 예에서.

사용자 정의 shell-command-switch하면 일반 대화 형 로그인 쉘 인 것처럼 프로파일을로드하는 쉘 프로세스를 얻을 수 있음을 발견했습니다 .

(setq shell-command-switch (Purecopy "-ic"))
(setq explicit-bash-args '( "-ic" "EMACS 내보내기; stty echo; bash"))

exec-path-from-shell 도 사용하고 있습니다.

~/.bashrc파일 이 있다고 가정 해보십시오 .

...

평가 "$ (direnv hook $ 0)"
에코 "foo"

내부 ~/code/foo에는 다음 .envrc과 같은 파일이 있습니다.

내보내기 PATH = $ PWD / bin : $ PATH
에코 "바"

나는 실행하는 경우 M-x shelldefault-directory로 설정 ~/code/foo, bash 쉘이 올바르게 내 프로필을로드하고 내 길에 저를 추가 할 direnv 후크를 실행합니다 :

direnv : .envrc로드 중
바
direnv : 내보내기 ~ PATH
~ / code / foo $ echo $ PATH
/ Users / username / code / foo / bin : / usr / local / bin : ... # 나머지 $ PATH

그러나 default-directory여전히 ~/code/foo이고 run M-! echo $PATH이면 .bashrc를 올바르게로드하지만 현재 디렉토리의 direnv 후크를 실행하지 않습니다.

푸
/ usr / local / bin : ... # ./bin이없는 $ PATH의 나머지

내가 실행하면 동일한 결과가 나타납니다 M-! cd ~/code/foo && echo $PATH.

내가 조언 또는으로 연결할 수있는 방법이 있나요 shell-command또는 start-process이 대화 형 쉘 버퍼로부터 전송되는 것처럼이 동작하도록하려면?


당신의 direnv 훅은 어떻게 생겼습니까? ~ / .bashrc에 정의되어 (setq shell-command-switch "-ic")있고 평가 한 경우 ~ / .bashrc의 다른 모든 명령과 함께 평가해야합니다.
rekado

~ / .bashrc의 줄은 eval "$(direnv hook $0)"입니다. 이것은 실행되지만 .envrc파일이 있는 특정 디렉토리에있을 때 실행되어야하는 메커니즘 은 작동하지 않습니다.
waymondo

.envrc파일에 아무것도 평가되지 않습니까? 아니면 내 보내지 않은 환경 변수입니까? 이것을 재현 해 볼 수 있도록 완전한 예를 들어 주시겠습니까?
rekado

@rekado-한번 봐 주셔서 감사합니다. 재현하기 위해 더 명확하게 질문을 업데이트했습니다.
waymondo

답변:


5

이것은 Emacs에는 문제가 아닌 bash에 문제가있는 것 같습니다. 쉘에서 shell-command실행 call-process하고 인수를 전달합니다. 나는 이것을 일반 쉘에서 시도했다.

bash -ic "cd ~/code/foo && echo $PATH"

~/.bashrc소스가 있지만 direnv 후크가 실행되지 않습니다. 경우 direnv hook bash실행되고, 함수 _direnv_hook의 출력과 앞에 추가 PROMPT_COMMAND.

_direnv_hook() {
  eval "$(direnv export bash)";
};
if ! [[ "$PROMPT_COMMAND" =~ _direnv_hook ]]; then
  PROMPT_COMMAND="_direnv_hook;$PROMPT_COMMAND";
fi

나는 PROMPT_COMMAND단순히 작동하지 않을 것이라고 생각합니다 . 그러나 _direnv_hook실제로는 간단 하기 때문에 문제가되지 않습니다 . 우리는 단순히 eval $(direnv export bash)쉘 명령 앞에 붙일 수 있으며 작동합니다 :

(let ((default-directory "~/code/foo/"))
  (shell-command "eval \"$(direnv export bash)\" && echo $PATH"))

메시지 버퍼에 대한 기능 보강 된 경로를 인쇄합니다. 또는 다음을 사용하여 실행하십시오 M-!.

cd ~/code/foo && eval "$(direnv export bash)" && echo $PATH

이 작업을 수행 할 필요는 없습니다 (setq shell-command-switch "-ic").


고마워, 이것이 정말로 올바른 길로 인도하는 데 도움이되었습니다. 나는 eval "$(direnv export bash)"ines를 추가하지 않는 솔루션을 찾고 있었지만 이것은 매우 도움이되었고 올바른 길로 안내했습니다.
waymondo

5

Running eval "$(direnv hook $0)"은에 연결되는 함수를 정의하며 프롬프트가 없기 때문에 $PROMPT_COMMANDbash가 실행될 때 호출 bash -ic되지 않습니다. 라인을 변경할 수 있습니다 :

eval "$(direnv hook $0)"

에:

eval "$(direnv hook $0)" && _direnv_hook

후크 함수를 명시 적으로 호출합니다.

편집 : 방금 rekado가 매우 유사한 대답을 주었다는 것을 깨달았습니다.


이것은 direnv가 어떻게 작동하는지에 익숙하지 않은 것을 지적하는 가장 간결한 답변입니다 $PROMPT_COMMAND.
waymondo

4

를 사용하여 direnv 후크가 작동하는 방식을 지적한 Rekado와 Erik에게 감사합니다 $PROMPT_COMMAND. shell-command프롬프트를 사용하지 않기 때문에 실행되지 않았습니다.

Erik의 대답은 set 을 M-!사용 하여 쉘 명령을 호출하는 예제에서 작동하지만 default-directory다음 예제에서는 작동하지 않습니다.

(let ((default-directory "~/code/"))
  (shell-command "cd ~/code/foo && echo $PATH"))

인터넷 검색 후 bash에서 명령을 실행하기 전에 무언가를 실행하기 위해 사전 실행 후크를 만드는 방법을 찾았습니다 . 나는이 아이디어를 가지고 direnv의 필요에 맞게 수정했습니다. 내 ~ / .bashrc의 관련 부분은 다음과 같습니다.

eval "$(direnv hook $0)"
direnv_preexec () {
  [ -n "$COMP_LINE" ] && return # don't execute on completion
  [ "$BASH_COMMAND" \< "$PROMPT_COMMAND" ] && return # don't double execute on prompt hook
  eval "$(direnv export bash)"
}
trap "direnv_preexec && $BASH_COMMAND" DEBUG

0

요즘 https://github.com/wbolster/emacs-direnv 를 사용하고 싶을 것입니다.

direnv가 쉘에 설치하는 후크와 유사하게 작동합니다. emacs 환경은 현재 디렉토리에 대한 올바른 환경이 어떤 direnv 상태와 일치하도록 요청시 (또는 버퍼를 전환 할 때 자동으로) 업데이트됩니다.

수정하여 exec-path하고 process-environment올바른 경로에서 오른쪽 환경 프로그램을 실행 쉘 할 것 같은 이맥스가 작동합니다.

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