Bash 프롬프트에서 디렉토리 이름 인용

Bash 프롬프트에서 디렉토리 이름 인용

프롬프트에서 현재 디렉터리를 참조하고 싶습니다.

예를 들어, 이렇게 하면:

mkdir $'new\nline'; cd $'new\nline'

$'new\nline'프롬프트 를 인쇄하는 대신 리터럴 개행 문자를 표시하고 싶습니다 .

\다음에서 백슬래시()를 인쇄하려고 하면 흥미로운 동작이 나타납니다 bash 5.0.9.

p='\\n'       && echo -E "${p@P}"  # 2 slashes; output = '\n'
p='\\\\n'     && echo -E "${p@P}"  # 4 slashes; output = '\n'
p='\\\\\\n'   && echo -E "${p@P}"  # 6 slashes; output = '\\n'
p='\\\\\\\\n' && echo -E "${p@P}"  # 8 slashes; output = '\\n'

노트:${parameter@P}parameter힌트인 것처럼 값을 확장한 결과인 문자열입니다.

출력이 (2와 4) 및 (6과 8) 슬래시와 동일한 이유는 무엇입니까?

이러한 혼란을 고려하면 다음과 같습니다.

mkdir '\\n' && cd '\\n'

\\n프롬프트에 : \\\\n또는 로 표시되도록 프로그래밍 방식으로 문자열로 변환하는 방법 $'\\\\n'과 리터럴 개행 상황을 처리하는 방법을 알 수 없습니다 .


프롬프트에서 참조되는 디렉터리 이름을 얻으려면 어떻게 해야 합니까? 예:

  • ~하위 디렉터리를 표시하고 그 $HOME앞에 표시~/
  • 필요한 경우에만 다른 경로를 탈출하세요
  • 표시 문자열의 복사-붙여넣기는 현재 디렉토리를 참조하는 유효한 쉘 토큰입니다.

예를 들어 "$HOME/dir with spaces"다음과 같아야 합니다.

  • ~/dir\ with\ spaces
  • ~/$'dir with spaces'
  • ~/'dir with spaces'

답변1

Bash는 프롬프트에 및를 포함하는 경우 에만 \w프롬프트에 cd $'/tmp/new\nline'표시됩니다 . /tmp/newline리터럴 줄 바꿈을 인쇄하지 않는 것 같지만 명시적인 출력 형식도 아닙니다.

${var@P}\u사용자 이름, \h호스트 이름, \w작업 디렉터리 와 같은 항목에 대해 프롬프트 이스케이프를 확장하도록 설계되었습니다 . 반대로 ${var@Q}어떤 인용 결과가 더 유용할까요?

settings PS1='${PWD@Q}\$ ', 프롬프트가 표시됩니다: $'/tmp/new\nline'$또는 '/tmp'$경로가 더 나은 경우. 또 다른 옵션은 PS1='$(printf "%q" "$PWD")\$ '경우에 따라 다른 따옴표를 제공하는 것입니다. 예를 들어 "좋은" 경로의 경우 따옴표를 생략합니다 /tmp$.


홈 디렉터리를 물결표로 표시하려면 한 가지 옵션은 수동으로 바꾸는 것입니다.

set_ppath() {
    printf -v ppath "%q" "$PWD"
    ppath="${ppath/$HOME/"~"}";
}
PROMPT_COMMAND=set_ppath
PS1='$ppath\$ '

아직도 언급하고 있어모두그러나 그 일부를 참조해야 하는 경우에는 경로입니다. 이 문제를 해결하려면 조금씩 이 길을 따라가야 한다고 생각합니다.


그런데 백슬래시가 왜 이렇게 접혀 있는지 모르겠습니다 ${var@P}.

답변2

ilkkachu의 답변을 바탕으로 다음을 생각해 냈습니다.

PROMPT_COMMAND=_prompt_bash_set

_prompt_bash_set() {
  # Working directory
  local prefix=''  # Used to contain '~' if $PWD directory is under $HOME
  local dir=$PWD

  # Replace leading $HOME with ~ if at beginning of string
  case "$PWD"/ in # Extra slash at end prevents substring match
    "$HOME"/)  # $PWD == $HOME itself
      prefix=\~  # no trailing /
      dir='' ;;
    "$HOME"/?*)  # $PWD is a subdir of $HOME
      prefix=\~/  # Add trailing / so that possibly quoted string goes after ~/ for path validity
      dir=${PWD#$HOME/} ;;   # Remove $HOME and / as this is now in $prefix
  esac

  if [[ $PWD != $HOME ]]; then  # $PWD != $HOME
    # Avoid ${PWD@Q} as it produced a literal \n inside $''
    printf -v dir '%q' "$dir"  # Quote directory minus $HOME

    # Replace a single slash with 4!?! slashes
    # https://unix.stackexchange.com/q/543473/143394
    dir=${dir//\\/\\\\\\\\}

    # Prevent command and variable substitution:
    dir=${dir//\`/\\\`}  # escape ` as \`
    dir=${dir//\$/\\\$}  # escape $ as \$
  fi

  PS1='\u@\h:'$dir'\$ '
}

$PS1여기에는 변수를 통하지 않고 리터럴 텍스트로 참조된 디렉터리가 포함됩니다 .

계속할 수 있다는 장점이 있어요디렉토리의 컬러 슬래시내 눈은 분석하기가 더 쉽다고 생각합니다.

관련 정보