PS1과 PROMPT_COMMAND의 차이점은 무엇입니까?


108

이 멋진 스레드를 살펴보면서 몇 가지 예제에서

PS1="Blah Blah Blah"

그리고 약간의 사용

PROMPT_COMMAND="Blah Blah Blah"

(일부는 둘 다 사용) bash 셸에서 프롬프트를 설정할 때. 둘의 차이점은 무엇입니까? SO 검색과 약간의 광범위한 Google 검색조차도 결과를 얻지 못하므로 답변을 찾을 수있는 올바른 위치에 대한 링크조차도 감사 할 것입니다.

답변:



67

PROMPT_COMMAND는 일반 bash 문을 포함 할 수있는 반면 PS1 변수는 변수에 호스트 이름에 대한 '\ h'와 같은 특수 문자를 포함 할 수도 있습니다.

예를 들어 다음은 PROMPT_COMMAND와 PS1을 모두 사용하는 bash 프롬프트입니다. PROMPT_COMMAND의 bash 코드는 당신이 어떤 git 브랜치에 있을지 알아 내고 프롬프트에 마지막 실행 프로세스의 종료 상태, 호스트 이름 및 pwd의 기본 이름과 함께 표시합니다. RET 변수는 마지막으로 실행 된 프로그램의 반환 값을 저장합니다. 터미널에서 마지막으로 실행 한 프로그램의 오류와 오류 코드가 있는지 확인하는 것이 편리합니다. 전체 PROMPT_COMMAND 표현식을 둘러싼 '바깥쪽에 주목하십시오. 이 변수는 PROMPT_COMMAND 변수가 평가 될 때마다 재평가되도록 PS1을 포함합니다.

PROMPT_COMMAND='RET=$?;\
  BRANCH="";\
  ERRMSG="";\
  if [[ $RET != 0 ]]; then\
    ERRMSG=" $RET";\
  fi;\
  if git branch &>/dev/null; then\
    BRANCH=$(git branch 2>/dev/null | grep \* |  cut -d " " -f 2);\
  fi;
PS1="$GREEN\u@\h $BLUE\W $CYAN$BRANCH$RED$ERRMSG \$ $LIGHT_GRAY";'

예제 출력은 git이 아닌 디렉토리에서 다음과 같습니다.

sashan@dhcp-au-122 Documents  $ false
sashan@dhcp-au-122 Documents  1 $ 

git 디렉토리에 브랜치 이름이 있습니다.

sashan@dhcp-au-122 rework mybranch $ 

최신 정보

댓글과 밥의 대답을 읽은 후 그가 설명하는대로 쓰는 것이 더 낫다고 생각합니다. PS1 변수는 PROMPT_COMMAND 내부에 설정되어있는 PROMPT_COMMAND 내부에 설정되어 있으며 런타임시 bash에 의해 평가되는 매우 복잡한 문자열 인 위에서 처음 작성한 것보다 유지 관리가 더 쉽습니다. 작동하지만 필요 이상으로 복잡합니다. 공정하게 말하면 약 10 년 전에 PROMPT_COMMAND를 직접 작성했는데 효과가 있었지만 그렇게 많이 생각하지 않았습니다.

내 물건을 어떻게 수정했는지 궁금한 사람들을 위해 기본적으로 PROMPT_COMMAND에 대한 코드를 별도의 파일 (Bob이 설명한대로)에 넣은 다음 PS1이 될 문자열을 에코합니다.

GREEN="\[\033[0;32m\]"
CYAN="\[\033[0;36m\]"
RED="\[\033[0;31m\]"
PURPLE="\[\033[0;35m\]"
BROWN="\[\033[0;33m\]"
LIGHT_GRAY="\[\033[0;37m\]"
LIGHT_BLUE="\[\033[1;34m\]"
LIGHT_GREEN="\[\033[1;32m\]"
LIGHT_CYAN="\[\033[1;36m\]"
LIGHT_RED="\[\033[1;31m\]"
LIGHT_PURPLE="\[\033[1;35m\]"
YELLOW="\[\033[1;33m\]"
WHITE="\[\033[1;37m\]"
RESTORE="\[\033[0m\]" #0m restores to the terminal's default colour

if [ -z $SCHROOT_CHROOT_NAME ]; then
    SCHROOT_CHROOT_NAME=" "
fi
BRANCH=""
ERRMSG=""
RET=$1
if [[ $RET != 0 ]]; then
    ERRMSG=" $RET"
fi
if which git &>/dev/null; then
    BRANCH=$(git branch 2>/dev/null | grep \* |  cut -d " " -f 2)
else
    BRANCH="(git not installed)"
fi
echo "${GREEN}\u@\h${SCHROOT_CHROOT_NAME}${BLUE}\w \
${CYAN}${BRANCH}${RED}${ERRMSG} \$ $RESTORE"

내 .bashrc

function prompt_command {
    RET=$?
    export PS1=$(~/.bash_prompt_command $RET)
}
PROMPT_DIRTRIM=3
export PROMPT_COMMAND=prompt_command

1
줄 중 하나를 줄일 수 있습니다 : if git branch &>/dev/null ; then\ . stdout과 stderr를 모두 / dev / null로 리디렉션합니다. tldp.org/LDP/abs/html/io-redirection.html

3
내보낼 필요가 없습니다 PROMPT_COMMAND.
고인돌

2
나는 ceving의 의견이이 답변에 대해서도 매우 사실이라고 생각합니다.Don't set PS1 in PROMPT_COMMAND! Set variables in PROMPT_COMMAND and use them in PS1
phil294

2
이유가 보이지 않는데, PS1내부에서 온라인으로 변경하는 PROMPT_COMMAND것이 불리한 이유 입니다. 완벽한 유용한 코드입니다. Bob의 대답과 달리 PS1변수는 올바르게 구성되었습니다. 이것은 실제 상황에 따라 훨씬 더 정교한 bash 프롬프트를 허용합니다.
Christian Wolf

2
@ChristianWolf PS1내부 구조는 PROMPT_COMMAND목적이 없습니다. 그것을하지 않는 방법의 예입니다. PS1에서 한 번 생성 .bash_profile하고 큰 따옴표 대신 작은 따옴표를 사용하면 각 프롬프트 중에 변수 대체가 평가됩니다.
pal

46

차이점은 PS1은 실제 사용되는 프롬프트 문자열이고 PROMPT_COMMAND는 프롬프트 직전에 실행되는 명령이라는 것입니다. 가장 간단하고 유연한 프롬프트 작성 방법을 원한다면 다음을 시도하십시오.

이것을 .bashrc에 넣으십시오.

function prompt_command {
  export PS1=$(~/bin/bash_prompt)
}
export PROMPT_COMMAND=prompt_command

그런 다음 스크립트 (bash, perl, ruby ​​: 원하는대로)를 작성하고 ~ / bin / bash_prompt에 배치합니다.

스크립트는 원하는 정보를 사용하여 프롬프트를 구성 할 수 있습니다. PS1 변수 용으로 개발 된 다소 바로크 식 대체 언어를 배울 필요가 없기 때문에 이것은 훨씬 더 간단한 IMO입니다.

PROMPT_COMMAND를 ~ / bin / bash_prompt로 직접 설정하고 PS1을 빈 문자열로 설정하면 동일한 작업을 수행 할 수 있다고 생각할 수 있습니다. 이것은 처음에는 작동하는 것처럼 보이지만 곧 readline 코드가 PS1이 실제 프롬프트로 설정 될 것으로 예상하고 역사에서 백 워드를 스크롤하면 결과적으로 엉망이된다는 것을 곧 알게됩니다. 이 해결 방법을 사용하면 PS1이 항상 최신 프롬프트를 반영하고 (함수가 셸의 호출 인스턴스에서 사용하는 실제 PS1을 설정하기 때문에) readline 및 명령 기록이 제대로 작동합니다.


17
수행 설정하지 PS1PROMPT_COMMAND! 에서 변수를 설정 PROMPT_COMMAND하고 PS1. 그렇지 않으면 당신은 당신이 사용할 수있는 기능 느슨한 것 PS1같은 이스케이프 시퀀스를 \u또는 \h. 당신은 그것들을 PROMPT_COMMAND. 즉 가능할 수도 있지만 그것의 잃게 해결하려면 수 없습니다 \[\]있는 비 인쇄 문자의 시작과 끝을 표시합니다. 즉, 프롬프트 길이에 대해 터미널을 혼동하지 않고 색상을 사용할 수 없습니다. 그리고 이것은 readline두 줄을 생성하는 명령을 편집 할 때 혼동을 줍니다. 결국 화면에 큰 혼란이 생깁니다.
2008 년

1
@ceving 사실! PROMPT_COMMAND를 사용 하여 PS1 의 형식 을 변경하고 두 세계를
최대한 활용할 수 있습니다

3
PROMPT_COMMAND인쇄 전에 실행됩니다 PS1. 나는 아무 문제가 설정되지 참조 PS1내부에서 PROMPT_COMMAND후하기 때문에, PROMPT_COMMAND완료, 쉘이 인쇄됩니다 PS1에서 수정 된, PROMPT_COMMAND(또는이 경우, 내부 prompt_command)?
Felipe Alvarez

3
경고 : PROMPT_COMMAND는 일반적으로 프롬프트에 직접 문자를 인쇄하는 데 사용해서는 안됩니다. PS1 외부에 인쇄 된 문자는 Bash에서 계산되지 않으므로 커서가 잘못 배치되고 문자가 지워집니다. PROMPT_COMMAND를 사용하여 PS1을 설정하거나 포함 명령을 확인하십시오. ( Arch Wiki Source )
meffect

3
나는 왜 모두가 PS1에서 명령 대체를 사용하는 대신 PROMPT_COMMAND에서 몇 가지 트릭을 시도하려고 시도하는 이유를 이해하지 못합니다. export PS1='$(~/bin/bash_prompt)'버그가 정상인 것처럼 보입니다
pal

10

에서 man bash:

PROMPT_COMMAND

설정된 경우 값은 각 기본 프롬프트를 실행하기 전에 명령으로 실행됩니다.

PS1

이 매개 변수의 값은 확장되고 (아래 PROMPTING 참조) 기본 프롬프트 문자열로 사용됩니다. 기본값은 ''\ s- \ v \ $ ''입니다.

단순히 프롬프트 문자열을 설정하려면 PS1단독으로 사용하면됩니다 .

PS1='user \u on host \h$ '

프롬프트를 인쇄하기 직전에 다른 작업을 수행하려면을 사용하십시오 PROMPT_COMMAND. 예를 들어 캐시 된 쓰기를 디스크에 동기화하려는 경우 다음과 같이 작성할 수 있습니다.

PROMPT_COMMAND='sync'

1
제목 을 설정하는 시퀀스를 및 로 래핑 할 수 있으므로 PS1필요없이 터미널 PROMPT_COMMAND의 제목을 설정할 수도 있습니다 . PS1\[\]
고인돌

1
@dolmen 좋아요. 그런 다음 환경 변수를 동적으로 설정하는 것과 같은 다른 작업을 수행해 보겠습니다.
Cyker

@Cyker에서 환경 변수를 동적으로 설정할 수 있으며 PS1, 서브 쉘에 설정 될 뿐이므로 값을 되돌릴 수 없습니다. 하지만 당신의 예는 사소한 것입니다PS1='$(sync)user \u on host \h$ '
pal

1

차이점은

  • 에서 불완전한 줄을 출력하면 PROMPT_COMMANDbash 프롬프트가 망가집니다.
  • PS1대리자 \H와 친구
  • PROMPT_COMMAND내용을 실행하고 내용 PS1을 프롬프트로 사용합니다.

PS1각 프롬프트에서 변수 확장 및 명령 대체를 수행하므로 PROMPT_COMMAND값을 할당 PS1하거나 임의의 코드를 실행 하는 데 사용할 필요가 없습니다 . export PS1='$(uuidgen) $RANDOM'에서 한 번 쉽게 할 수 있습니다. .bash_profile작은 따옴표 만 사용 하면됩니다 .


0

예, 이걸 정말 잘하려고 노력하세요.

  • PROMPT_COMMAND편리한 bash 편의 변수 / 함수이지만 엄밀히 말해서 PS1단독으로 사용할 수없는 것은 없습니다 . 맞습니까?

즉, 프롬프트 외부의 범위 를 사용하여 다른 변수 를 설정 하려면 쉘에 따라 해당 변수를 먼저 외부에서 선언해야 $PS1하거나 (최악의 경우) 전에 FIFO에서 대기하는 것으로 멋지게 만들어야 할 수도 있습니다. 호출 $PS1(그리고 끝에서 다시 무장 $PS1); 은 \u \h당신이 어떤 멋진 정규식을 사용하는 경우 특히, 몇 가지 문제가 발생할 수 있습니다; 그러나 그렇지 않은 경우 : PROMPT_COMMAND명령 대체를 사용하여 할 수있는 모든 작업을 수행 할 수 $PS1있습니까 (그리고 아마도 코너의 경우 명시적인 하위 쉘)?

권리?

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