>source

최근에 라는 함수를 작성했습니다.zuperPrompt멋진 프롬프트를 출력하고 내 .zshrc에 PROMPT 변수를 설정하여 다음과 같이 해당 함수를 호출합니다.

setopt PROMPT_SUBST
PROMPT='$(zuperPrompt)'

발견된 것과 동일한 문제이지만 awk 명령에서 개행 이스케이프 문자를 사용하는 데 문제가 있었던 것 같습니다. 줄 바꿈 문자 없이 전체 프롬프트를 수행하려고 시도했지만 동일한 결과를 얻었습니다.

기능은 다음과 같습니다.

zuperPrompt() {
    # count chars in directory name
    num_chars=1
    if [ ! $(dirs)= '~' ]; then
       let "num_chars=$(basename "`pwd`" | wc -m) -1"
    fi
    # draw line
    line="\n╭──"
    for i in {1..$num_chars}; do
       line+="─"
    done
    line+="──╯"
    directory="%F{8}%K{8}%B%F{blue}%1~%k%F{8}"
    arrows="%B%F{magenta}❯%B%F{yellow}❯%F{cyan}❯ "
    row1="\n%B%F{green}◆ "$directory"─╮"
    row2=$line
    row3="\n╰─ "$arrows
    print -P $row1$row2$row3
}

입력 후 탭을 누른 결과는 다음과 같습니다.파이썬3

여기서 무슨 일이 일어나고 있는지 잘 모르겠습니다. 누군가 도울 수 있다면 미리 감사드립니다!

이것이 귀하의 질문에 대한 답변입니까? zsh 프롬프트가 제대로 이스케이프되지 않았습니다.

Thomas Dickey2022-02-07 08:45:16

답변 감사합니다, 토마스. 아니요, 불행히도 (관련되어 있고 내가 알지 못하는 경우 제외). 중괄호의 인스턴스가 없습니다.

Sam2022-02-07 08:45:16
  • 답변 # 1

    함께프롬프트 서브스트옵션을 켜면 프롬프트 확장 시 매개변수 확장, 명령 대체산술 확장을 확장할 수 있으므로 다음을 수행할 수 있습니다.PS1='$(PS1을 동적으로 생성하는 명령)', 하지만 해당 확장의 결과는 여전히 프롬프트 문자열이 되어야 합니다.%~/%중확장됩니다.

    마지막으로 하고 싶은 일은PS1을 동적으로 생성하는 명령전화하다인쇄 -P. 오히려 반대여야 합니다. 만약PS1을 동적으로 생성하는 명령출력은 문자 그대로 표시되어야 하므로%(그리고!만약프롬프트뱅켜져 있음) 이스케이프 처리되고 커서를 이동하지 않는 모든 제어 시퀀스는%{,%}, 등.

    동적 텍스트를 포함하는 또 다른 zsh-y 접근 방식$PS1그 외에는 모두%엑스이스케이프가 제공할 수 있는 것은 설정하지 않는 것입니다.$promptsubst그러나 동적 텍스트를precmd후크에 넣고 보관하십시오.$psvar참조하는 멤버의 배열%1v,%2v... 에$PS1.

    대신:

    command-that-generates-PS1-dynamically() {
      local some_dynamic_data=$(some-cmd)
      print -r --"%F{red}${some_dynamic_data//\%/%%}%f$ "
    }
    set -o promptsubst
    PS1='$(command-that-generates-PS1-dynamically)'
    

    (와${some_dynamic_data//\%/%%}탈출에만 신경쓰고%s, 취급하지 않음!이스케이프 시퀀스도$some_dynamic_data포함할 수 있음).

    해야 할 일:

    prompt-hook() {
      psvar[1]=$(some-cmd)
    }
    precmd_function+=(prompt-hook)
    PS1='%F{red}%1v%f$ '
    

    또한 서브쉘을 분기할 필요가 없습니다(이를 통해프롬프트 후크프롬프트 확장에서 일부 데이터를 유지하기 위해),%1v확장(인쇄 가능한 텍스트용)은 인쇄할 수 없는 문자가 보이도록 처리하거나 변환합니다.

    귀하의 경우 다음과 같이 보일 수 있습니다.

    display_width() REPLY=$(($#1 * 3 -${#${(ml[$#1 * 2])1}}))
    prompt-hook() {
      display_width ${(%):-%1~}
      psvar[1]=${(l[$REPLY][─])}
    }
    precmd_functions+=(prompt-hook)
    () {
      local directory='%F{8}%K{8}%F{blue}%1~%k%F{8}'
      local arrows='%B%F{magenta}❯%F{yellow}❯%F{cyan}❯'
      local line=$'─╮\n╭──%1v──╯\n╰─'
      PS1=$'\n'"%B%F{green}◆ ${directory}${line} ${arrows}%b%f "
    }
    

    어디$PS1정적입니다(필요 없음$promptsubst; 여기서는 가독성을 향상시키기 위해 임시 임시 변수를 사용하지만 동적 사용자 지정 부분(선에서 확장의 표시 너비와 길이가 같아야 하는 부분)%1~)는 우리의 일부로 생성됩니다.precmd훅.

    이 과정에서 서브쉘이 분기되지 않는다는 것을 알 수 있습니다.

    참조 문자열의 표시 너비 가져오기그것에 대한 자세한 내용은display_width문자열의 표시 너비를 계산하는 함수입니다(반드시 문자열의 문자 수와 같을 필요는 없습니다).

  • 답변 # 2

    기본 프롬프트 문자열zshshell은 할당된 문자열입니다.즉각적인또는PS1변하기 쉬운. 여기에는 문자열을 표시되는 프롬프트로 동적으로 확장하는 방법에 대해 쉘에 알리는 다양한 이스케이프 문자와 code가 포함될 수 있습니다.

    다음을 사용하여 프롬프트 문자열을 직접 확장할 수 있습니다.인쇄 -rP --$PROMPT또는인쇄 -rP --$PS1.

    그러나 문자열을 할당하면즉각적인이미 확장한인쇄 -P, 프롬프트 문자열의 어떤 부분이 표시되고 프롬프트 문자열의 어떤 부분이 터미널 code인지를 쉘에 알려주는 이스케이프 code입니다. 색상이 변경되면 쉘은 더 이상 프롬프트의 크기를 추적할 수 없습니다. 이것은 귀하가 설명하는 문제 유형을 발생시킵니다. 일반적인 다른 문제는 긴 명령에 대한 줄 바꿈이 지저분해진다는 것입니다.

    따라서 사용하지 마십시오.인쇄 -P나중에 할당되는 문자열을 생성하기 위해즉각적인하지만 대신인쇄 -r"원시"로 출력합니다.

    에 설명된 것과 동일한 문제입니다. zsh 프롬프트가 제대로 이스케이프되지 않았습니다., 그러나 약간 다른 원인이 있습니다(인쇄되지 않는 문자에 대한 정보를 추가하지 않는 대신 프롬프트 문자열에서 인쇄되지 않는 문자에 대한 유용한 정보를 제거합니다).


    약간 어색한 code

    num_chars=1
    if [ ! $(dirs)= '~' ]; then
       let "num_chars=$(basename "`pwd`" | wc -m) -1"
    fi
    

    한 줄로 작성할 수 있습니다.

    num_chars=$( print -n -P '%1~' | wc -m )
    

    (%1~나중에 실제로 해당 문자열을 프롬프트에 포함하기 위해 사용하는 현재 디렉토리 이름에 대한 프롬프트 code입니다.)

    그리고 루프

    line="\n╭──"
    for i in {1..$num_chars}; do
       line+="─"
    done
    line+="──╯"
    

    다음과 같이 쓸 수 있습니다.

    printf -v line '\n╭──%*s──╯' $num_chars ''
    line=${line///─}
    

    하지만 다음과 같이 결합할 수 있습니다.

    print -v wd -n -P '%1~'
    printf -v line '\n╭──%*s──╯' $#wd ''
    line=${line///─}
    

    추악한 명령 대체 및 외부 호출을 제거합니다.화장실.

    @StéphaneChazelas 입력해 주셔서 감사합니다. 실제 질문과 대부분 관련이 없기 때문에 답변의 후반부를 그대로 두겠습니다(편집을 원하지 않는 한). print -r 정보 감사합니다!

    they2022-02-06 10:07:44
  • 이전 gnome : 바로 가기 키를 사용하여 kali Linux에서 응용 프로그램 간을 탐색하려면 어떻게 해야 합니까?
  • 다음 ubuntu : wall 명령으로 메시지를 보낼 수 없는 이유는 무엇입니까?