쉘 프롬프트에 명령이 주어졌는지 감지하는 방법

쉘 프롬프트에 명령이 주어졌는지 감지하는 방법

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에 따라 달라집니다. 너 자신을..bashrcPS1\#

관련 정보