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
결국에는 전혀 필요하지 않게 되었습니다. 나에게 올바른 방향을 알려준 크리스토퍼에게 감사드립니다.
대신 다음 파일을 고려하세요 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}
기본값 지정. 인수가 설정되지 않거나 비어 있으면 단어의 확장이 인수에 할당됩니다. 그런 다음 매개변수의 값을 바꿉니다.
따라서 __cmdnbary[\#]
설정되지 않거나 null인 경우 이 구문은 빈 문자열(이 경우 빈 문자열)을 할당 word
하고 전체 구문은 출력에서 동일한 빈 문자열로 대체됩니다.
__cmdnbary[\#]
~ 할 것이다언제나처음 볼 때 #은 단조롭기 때문에 설정되지 않거나 null이 됩니다. 항상 증가하거나 동일하게 유지됩니다. (즉, 반복될 때까지 아마도 2^31 또는 2^63 정도일 것입니다. 하지만 다른 문제가 발생하게 됩니다.긴우리가 거기 도착하기 전에. 제가 이 솔루션을 일종의 해킹이라고 설명하는 이유가 있습니다. )
조건식은 다음과 같습니다.${__cmdnbary[\#]-word}
${__cmdnbary[\#]-word}
또 다른 매개변수 확장입니다. 매뉴얼에서:
${parameter:-word}
기본값 사용. 인수가 설정되지 않거나 비어 있으면 단어의 확장이 대체됩니다. 그렇지 않으면 매개변수 값이 대체됩니다.
따라서 배열 항목이 다음과 같은 \#
경우설정되지 않았거나 비어 있음, 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}`.
${parameter:-word}
이는 null이거나 설정되지 않은 경우에만 나타납니다 word
. 우리의 경우에는 다음과 같은 경우에만 나타 납니다.parameter
아니요배열의 위치를 설정합니다. \#
증가하는 경우에만 이 작업을 수행하지 않습니다. 이는 방금 명령을 실행한 경우에만 발생합니다.
이는 에 대해 다음과 같은 경우 ${parameter:-word}
에만 렌더링한다는 것을 의미합니다.word
아니요우리가 원하는 것과 정반대의 명령이 실행됩니다. 그래서 우리는 ${parameter:-word}
그것을 대신 사용합니다. 다시, 매뉴얼에서:
${parameter:+word}
대체 값 사용. 인수가 비어 있거나 설정되지 않은 경우 아무것도 대체되지 않으며, 그렇지 않으면 단어의 확장이 대체됩니다.
이것은 (불행히도) 이해해야 할 이중 부정 논리이지만 거기에 있습니다.
프롬프트 자체
전환 메커니즘에 대해 설명했지만 프롬프트 자체는 어떻습니까?
$( ... )
여기에는 프롬프트의 내용을 포함하는 데 사용됩니다 . 주로 내 자신의 가독성을 위해 그렇게 할 필요는 없습니다. $( ... )
일반적으로 변수 할당에 채우는 내용으로 바꿀 수 있습니다 .
왜 해킹인가요?
희소 배열에 항목을 어떻게 추가했는지 기억하시나요? 우리는 이러한 항목을 삭제하지 않으므로 쉘 세션을 종료할 때까지 배열이 영원히 커집니다 PS1
. 제가 아는 한 방법은 없습니다설정되지 않음프롬프트의 변수 또는 배열 위치입니다. 시도해 볼 수도 있지만 $()
작동하지 않는다는 것을 알게 될 것입니다. 하위 쉘 내의 변수 네임스페이스에 대한 변경 사항은 파생된 하위 쉘의 공간에 적용되지 않습니다.
너가능한할당 전 및 결과 파일의 내용 정보를 mktmp
초기에 사용해 보십시오. 그런 다음 현재 내용을 저장된 내용과 비교할 수 있지만 이제 프롬프트는 비상 시 디스크 I/O에 따라 달라집니다. 너 자신을..bashrc
PS1
\#