
PROMPT_COMMAND
나는 바로 이전에 명령 프롬프트에 제공된 내용에 응답하는 를 작성하고 싶습니다 . 예를 들어, 다음과 같이 광범위하고 정보가 풍부한 프롬프트와 간단하고 간결한 프롬프트 사이를 전환하려면:
mikemol@serenity ~ $ echo hi
hi
$ echo ho
ho
$ echo hum
hum
$
mikemol@serenity ~ $
값은 비어 있지 않은 경우에만 셸 기록에 추가되는 것으로 나타나므로 가장 최근 기록 항목이 비어 있는지 간단히 테스트할 수는 없습니다. set | grep some_command
실행 후 실행하면 some_command
아무 것도 제공되지 않으므로 해당 정보가 포함된 환경 변수가 나타나지 않습니다.
저는 주로 를 사용 bash
하지만 POSIX 호환 솔루션과 기타 셸에 대해 궁금합니다.
답변1
나는 궁극적으로 PROMPT_COMMAND
전혀 필요하지 않았습니다. 나에게 올바른 방향을 알려준 Christopher에게 감사드립니다.
대신 다음 파일을 고려해보세요 ps1.prompt
.
${__cmdnbary[\#]+$(
echo '\u@\h: \w' # Your fancy prompt goes here, with all the usual special characters available.
) }${__cmdnbary[\#]=}\$
그런 다음 이것을 내 PS1
:
PS1=$(cat ps1.prompt)
(이렇게 할 필요는 없지만 일러스트레이션이나 편집에는 편리하다고 생각했습니다.)
그래서 우리는 다음을 봅니다:
mikemol@zoe:~$ echo hi
hi
mikemol@zoe:~$ echo ho
ho
mikemol@zoe:~$ echo hum
hum
mikemol@zoe:~$
mikemol@zoe:~$ PS1=$(cat ps1.prompt)
$
mikemol@zoe: ~ $ echo hi
hi
$ echo ho
ho
$ echo hum
hum
$
mikemol@zoe: ~ $
우리는 배열 핵을 사용하고 있습니다여기서 시연bash
하지만 의 매개변수 대체를 사용하는 대신 이전 명령이 실행되지 않은 경우에만 트리거하도록 ${parameter:-word}
사용합니다 .${parameter+word}
논리에서 이중 부정을 사용해야 하므로 이에 대한 설명이 필요합니다.
${__cmdnbary[\#]-word}${__cmdnbary[\#]=}
작동 원리
원래 배열 해킹 데모에서는 해당 구성이 ${__cmdnbary[\#]-word}${__cmdnbary[\#]=}
사용되었습니다. (명확성을 위해 $?
로 대체했습니다 word
). 매개변수 확장과 배열에 특별히 익숙하지 않다면(저는 익숙하지 않았습니다), 무슨 일이 일어나고 있는지 전혀 명확하지 않습니다.
첫째, 이해하다\#
당매뉴얼:
\#
이 명령의 명령 번호
...
명령 번호는 현재 셸 세션 동안 실행되는 명령 순서의 위치입니다.
이는 \#
단지 변경 사항이 있음을 의미합니다.만약에 그리고 만약에명령이 실행됩니다. 사용자가 프롬프트에 빈 줄을 입력하면 명령이 실행되지 않으므로 \#
변경되지 않습니다.
${__cmdnbary[#]=}에 빈 문자열 설정
${__cmdnbary[\#]=}
매개변수 확장을 사용합니다. 다음으로 돌아가기매뉴얼:
${parameter:=word}
기본값 할당. 매개변수가 설정되지 않거나 null인 경우 단어의 확장이 매개변수에 할당됩니다. 그런 다음 매개변수의 값이 대체됩니다.
따라서 __cmdnbary[\#]
가 설정되지 않거나 null인 경우 이 구문은 빈 문자열(우리의 경우 는 빈 문자열)을 할당 word
하고 전체 구문은 출력에서 동일한 빈 문자열로 대체됩니다.
__cmdnbary[\#]
~ 할 것이다언제나#은 단조롭기 때문에 처음 볼 때 설정되지 않거나 null이어야 합니다. 항상 증가하거나 동일하게 유지됩니다. (즉, 반복될 때까지 2^31 또는 2^63 정도일 가능성이 높지만 다른 문제가 발생할 수 있습니다.긴우리가 거기 도착하기 전에. 내가 이 솔루션을 약간의 해킹이라고 설명하는 이유가 있습니다.)
조건부${__cmdnbary[\#]-word}
${__cmdnbary[\#]-word}
또 다른 매개변수 확장입니다. 매뉴얼에서:
${parameter:-word}
기본값 사용. 매개변수가 설정되지 않거나 null이면 단어의 확장이 대체됩니다. 그렇지 않으면 매개변수 값이 대체됩니다.
따라서 배열 항목이 다음과 \#
같다 면설정되지 않았거나 null, word
그 자리에 사용됩니다. 우리는 그것을 확인할 때까지 __cmdnbary[\#]
(대체를 사용하여 ) 할당을 시도하지 않기 때문에 ${parameter:=word}
처음으로 주어진 것을 확인할 때 \#
배열에서 해당 위치가 설정되지 않은 것을 찾아야 합니다.
bash
희소 배열을 사용합니다
C 스타일 배열에 익숙한 사람들을 위한 한 가지 설명입니다. bash
실제로 사용희소 배열; 할당할 때까지무엇배열의 특정 위치로 이동하면 해당 위치가 설정 해제됩니다. 빈 문자열은 "null 또는 설정되지 않음"과 동일하지 않습니다.
대신 ${__cmdnbary[#]+word}${__cmdnbary[#]=}를 사용하는 이유
${__cmdnbary[\#]+word}${__cmdnbary[\#]=}
및 ${__cmdnbary[#]-word}${__cmdnbary[#]=} look very siilar. The *only* thing we change between the two constructs can be found in the first portion; we use
${parameter:+word} instead of
${parameter:-word}`.
with 는 ${parameter:-word}
null 이거나 설정되지 않은 word
경우에만 표시됩니다 parameter
. 우리의 경우에는아직\#
배열의 위치를 아직 설정합니다. 이는 증가한 경우에만 수행되지 않으며 방금 명령을 실행한 경우에만 발생합니다.
즉, 를 사용하면 다음과 같은 경우 ${parameter:-word}
에만 발표할 것입니다.word
아직우리가 원하는 것과 정확히 반대되는 명령을 실행했습니다. 그래서 ${parameter:-word}
대신 사용합니다. 다시, 매뉴얼에서:
${parameter:+word}
대체 값 사용. 매개변수가 null이거나 설정되지 않은 경우 아무것도 대체되지 않으며, 그렇지 않으면 단어 확장이 대체됩니다.
(불행히도) 이해해야 할 이중 부정 논리가 더 많지만 여기까지입니다.
프롬프트 자체
전환 메커니즘에 대해 설명했지만 프롬프트 자체는 어떻습니까?
여기서는 $( ... )
프롬프트의 내용을 담는 데 사용합니다. 주로 가독성에 대한 나 자신의 이익을 위해; 그렇게 할 필요는 없습니다. $( ... )
일반적으로 변수 할당에 포함할 수 있는 항목으로 바꿀 수 있습니다 .
왜 해킹인가요?
희소 배열에 항목을 추가하는 방법을 기억하시나요? 우리는 해당 항목을 제거하지 않으므로 쉘 세션이 종료될 때까지 배열이 영원히 커집니다. 껍질이 새고 있습니다 PS1
. 그리고 내가 아는 한, 그럴 방법은 없어설정되지 않음프롬프트의 변수 또는 배열 위치. 에서 시도해 볼 수는 있지만 $()
작동하지 않는다는 것을 알게 될 것입니다. 서브셸 내부의 변수 네임스페이스에 대한 변경 사항은 서브셸이 분기된 공간에 적용되지 않습니다.
너~할 것 같다mktmp
의 초기 .bashrc
, PS1
할당 전 및 결과 파일의 정보를 사용해 보십시오 . 그런 다음 현재 상태를 \#
거기에 저장한 것과 비교할 수 있지만 이제 프롬프트를 디스크 I/O에 종속되게 만들었습니다. 이는 긴급 상황에서 자신을 잠글 수 있는 좋은 방법입니다.