프롬프트의 일부를 오른쪽 정렬


27

터미널 창의 오른쪽에 프롬프트의 일부가 정렬 된 다음 두 번째 줄에서 실제 커서가 시작되는 것을 보았습니다. PS1에서 "\ n"으로 두 번째 줄을 얻을 수 있지만 그 부분을 오른쪽에 맞추는 방법을 알 수 없습니다. 두 문자열 사이에 공백이 추가 된 것을 보았습니까?

답변:


17

프롬프트를 표시하기 전에 첫 번째 행을 표시하면 원하는 작업을 쉽게 수행 할 수 있습니다. 예를 들어, 다음 \w은 첫 번째 줄의 왼쪽에 프롬프트와 첫 번째 줄 \u@\h의 오른쪽에 프롬프트를 표시합니다. $COLUMNS터미널 너비를 포함 하는 변수와 $PROMPT_COMMANDbash가 프롬프트를 표시하기 전에 평가 되는 매개 변수를 사용합니다.

print_pre_prompt () 
{ 
    PS1L=$PWD
    if [[ $PS1L/ = "$HOME"/* ]]; then PS1L=\~${PS1L#$HOME}; fi
    PS1R=$USER@$HOSTNAME
    printf "%s%$(($COLUMNS-${#PS1L}))s" "$PS1L" "$PS1R"
}
PROMPT_COMMAND=print_pre_prompt

3
인쇄되지 않은 문자는 문자열 길이가 표시되는 문자 수와 같지 않기 때문에 왼쪽의 채색 프롬프트를 원하면 상황이 훨씬 더 복잡해집니다.
Mu Mind

1
모두 이것과 가장 높은 경우 제대로 작동하지 않습니다 대답을 선정 .inputrc있다 set show-mode-in-prompt on. 모두 비 prinable의 길이를 계산하지 않는 ANSI CSI 코드를 , 제대로 묶하지 않는 \[\]@Mu 마음에서 언급 한 바와 같이. 해결책이 답변 을 참조하십시오 .
Tom Hale

26

여기에서 찾은 정보를 기반으로 색상에 대한 지원을 포함하여 오른쪽 또는 왼쪽의 가변 길이 내용을 수용하면서 오른쪽 정렬을위한 더 간단한 솔루션을 찾을 수있었습니다. 귀하의 편의를 위해 여기에 추가 ...

색상에 대한 참고 사항 : 그룹화 \033없이 대안을 선호 하여 이스케이프를 사용하면 \[\]가장 호환 가능하므로 권장됩니다.

트릭은 오른쪽을 먼저 쓴 다음 캐리지 리턴 ( \r)을 사용 하여 줄의 시작으로 돌아가서 왼쪽 내용을 계속 덮어 씁니다.

prompt() {
    PS1=$(printf "%*s\r%s\n\$ " "$(tput cols)" 'right' 'left')
}
PROMPT_COMMAND=prompt

내가 사용하고 있습니다 tput cols에서 터미널 / 콘솔 폭을 검색하는 맥 OS X에 terminfo내 이후 $COLUMNSvar에 채워되지 않습니다 env하지만 당신은 교체 "대체 할 수 있습니다 *"의 값을 %*s제공하여, "${COLUMNS} ", 또는 다른 어떤 값 대신, 선호합니다.

다음 예제는 $RANDOM다른 길이의 컨텐츠를 생성 하는 데 사용 하는 색상을 포함하며 구현을 재사용 가능한 함수로 리팩토링하기 위해 함수를 추출하는 방법을 보여줍니다.

function prompt_right() {
  echo -e "\033[0;36m$(echo ${RANDOM})\033[0m"
}

function prompt_left() {
  echo -e "\033[0;35m${RANDOM}\033[0m"
}

function prompt() {
    compensate=11
    PS1=$(printf "%*s\r%s\n\$ " "$(($(tput cols)+${compensate}))" "$(prompt_right)" "$(prompt_left)")
}
PROMPT_COMMAND=prompt

printf문자열의 길이를 문자 수로 간주하여 색상을 렌더링하는 데 필요한 문자 수를 보상해야하므로 보상없이 인쇄되지 않은 ANSI 문자로 인해 항상 화면 끝보다 짧습니다. 색상에 필요한 문자는 일정하게 유지되며 printf는 다음과 같이 반환 된 길이의 변화를 고려합니다.$RANDOM 예를 들어 올바른 정렬을 유지합니다.

이것은 (예. 배쉬 프롬프트 이스케이프 시퀀스 경우가 아니라 \u, \w, \h, \t프롬프트가 표시 될 때 printf와 문자열을 렌더링 한 후 bash는 단지 그들을 변환하기 때문에이 단지 2의 길이를 기록합니다 같이)하지만. 왼쪽에는 영향을 미치지 않지만 오른쪽에는 피하는 것이 가장 좋습니다.

생성 된 컨텐츠가 일정한 길이로 유지 될 경우 아무런 결과가 없습니다. \t24 시간 동안 항상 같은 양의 문자 (8)를 렌더링 하는 시간 옵션과 같습니다. 이 경우 인쇄시 8 자까지 계산 된 2 자 사이의 차이를 수용하기 위해 필요한 보정 만 고려하면됩니다.

\\\문자열에 의미가있는 일부 이스케이프 시퀀스 를 세 번 이스케이프해야 할 수도 있습니다. 다음 예제와 같이 현재 작업 디렉토리 이스케이프 \w는 다른 의미를 갖지 않으므로 예상대로 작동하지만 \t탭 문자를 의미하는 time 은 세 번 이스케이프하지 않으면 예상대로 작동하지 않습니다.

function prompt_right() {
  echo -e "\033[0;36m\\\t\033[0m"
}

function prompt_left() {
  echo -e "\033[0;35m\w\033[0m"
}

function prompt() {
    compensate=5
    PS1=$(printf "%*s\r%s\n\$ " "$(($(tput cols)+${compensate}))" "$(prompt_right)" "$(prompt_left)")
}
PROMPT_COMMAND=prompt

조이!


8

printf와 함께 사용하면 $COLUMNS실제로 다음과 같이 잘 작동합니다.

printf "%${COLUMNS}s\n" "hello"

그것은 나를 위해 완벽하게 정당화했습니다.


6

다음은 터미널의 RHS에서 현재 날짜와 시간을 빨간색으로 표시합니다.

# Create a string like:  "[ Apr 25 16:06 ]" with time in RED.
printf -v PS1RHS "\e[0m[ \e[0;1;31m%(%b %d %H:%M)T \e[0m]" -1 # -1 is current time

# Strip ANSI commands before counting length
# From: https://www.commandlinefu.com/commands/view/12043/remove-color-special-escape-ansi-codes-from-text-with-sed
PS1RHS_stripped=$(sed "s,\x1B\[[0-9;]*[a-zA-Z],,g" <<<"$PS1RHS")

# Reference: https://en.wikipedia.org/wiki/ANSI_escape_code
local Save='\e[s' # Save cursor position
local Rest='\e[u' # Restore cursor to save point

# Save cursor position, jump to right hand edge, then go left N columns where
# N is the length of the printable RHS string. Print the RHS string, then
# return to the saved position and print the LHS prompt.

# Note: "\[" and "\]" are used so that bash can calculate the number of
# printed characters so that the prompt doesn't do strange things when
# editing the entered text.

PS1="\[${Save}\e[${COLUMNS:-$(tput cols)}C\e[${#PS1RHS_stripped}D${PS1RHS}${Rest}\]${PS1}"

장점 :

  • RHS 프롬프트에서 색상 및 ANSI CSI 코드와 올바르게 작동
  • 하위 프로세스가 없습니다. shellcheck깨끗한.
  • 경우 올바르게 작동 .inputrc있다 set show-mode-in-prompt on.
  • 올바르게에 비 프롬프트 길이주는 문자를 캡슐화 \[하고 \]프롬프트에서 입력 한 텍스트를 편집하면 이상하게 다시 인쇄 프롬프트가 발생하지 않습니다 그래서.

참고 : 당신은 어떤 색상 시퀀스 수 있도록해야합니다 $PS1코드 전에 제대로 묶 exeucted됩니다 \[\]그들 중 어떤 중첩이 없습니다 것을.


이론적 으로이 접근법을 좋아하지만 실제로는 즉시 작동하지 않습니다 (ubuntu 18.04, GNU bash 4.4.19). 코드를 .bashrc에 직접 추가하면 먼저 오류가 발생합니다 bash: local: can only be used in a function. 이는 수정하기가 쉽지 않습니다. 그 후에 COLUMNS는 정의 되어 있지 않으므로 아무것도 표시하지 않습니다 $(tput cols). 로 대체해야 합니다. 스 니펫이 다른 파일에 저장된 후 소스로 제공되는 경우 동일한 결과 .bashrc.
Polentino

1
@Polentino에게 감사합니다. 설정되지 않은 tput cols경우 실행할 코드를 업데이트했습니다 $COLUMNS. 그리고 네,이 코드는 함수 안에 있어야합니다. PROMPT_COMMAND='_prompt_bash_set'함수를 사용 하고 이름을 지정합니다 _prompt_bash_set.
Tom Hale

2

방금 여기에 내 것을 던질 줄 알았는데 GRML zsh 프롬프트와 거의 동일합니다 (zsh 업데이트를 제외하고는 줄 바꿈 및 백 스페이스에서 조금 더 나은 프롬프트가 표시됩니다-bash에서는 복제가 불가능합니다. 적어도 현재로서는 매우 어렵습니다).

나는 이것에 좋은 3 일을 보냈습니다 (아치가 달린 랩톱에서만 테스트되었습니다). 그래서 스크린 샷과 ~ / .bashrc에 들어가는 것들이 있습니다 :)

bash 프롬프트의 스크린 샷

경고 -조금 미쳤어

옆 중요 -마다 ^[(예 :가 ^[[34m) 정말 이스케이프 문자입니다 (char)27. 나는이를 삽입하는 방법을 알고있는 유일한 방법은 입력하는 것입니다 ctrl+ ( [v) (즉, 모두를 공격 [하고 v있는 동안 ctrl아래로 개최됩니다.

# grml battery?
GRML_DISPLAY_BATTERY=1

# battery dir
if [ -d /sys/class/power_supply/BAT0 ]; then
    _PS1_bat_dir='BAT0';
else
    _PS1_bat_dir='BAT1';
fi

# ps1 return and battery
_PS1_ret(){
    # should be at beg of line (otherwise more complex stuff needed)
    RET=$?;

    # battery
    if [[ "$GRML_DISPLAY_BATTERY" == "1" ]]; then
        if [ -d /sys/class/power_supply/$_PS1_bat_dir ]; then
            # linux
            STATUS="$( cat /sys/class/power_supply/$_PS1_bat_dir/status )";
            if [ "$STATUS" = "Discharging" ]; then
                bat=$( printf ' v%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
            elif [ "$STATUS" = "Charging" ]; then
                bat=$( printf ' ^%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
            elif [ "$STATUS" = "Full" ] || [ "$STATUS" = "Unknown" ] && [ "$(cat /sys/class/power_supply/$_PS1_bat_dir/capacity)" -gt "98" ]; then
                bat=$( printf ' =%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
            else
                bat=$( printf ' ?%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
            fi;
        fi
    fi

    if [[ "$RET" -ne "0" ]]; then
        printf '\001%*s%s\r%s\002%s ' "$(tput cols)" ":( $bat " "^[[0;31;1m" "$RET"
    else
        printf '\001%*s%s\r\002' "$(tput cols)" "$bat "
    fi;
}

_HAS_GIT=$( type 'git' &> /dev/null );

# ps1 git branch
_PS1_git(){
    if ! $_HAS_GIT; then
        return 1;
    fi;
    if [ ! "$( git rev-parse --is-inside-git-dir 2> /dev/null )" ]; then
        return 2;
    fi
    branch="$( git symbolic-ref --short -q HEAD 2> /dev/null )"

    if [ "$branch" ]; then
        printf ' \001%s\002(\001%s\002git\001%s\002)\001%s\002-\001%s\002[\001%s\002%s\001%s\002]\001%s\002' "^[[0;35m" "^[[39m" "^[[35m" "^[[39m" "^[[35m" "^[[32m" "${branch}" "^[[35m" "^[[39m"
    fi;
}

# grml PS1 string
PS1="\n\[\e[F\e[0m\]\$(_PS1_ret)\[\e[34;1m\]${debian_chroot:+($debian_chroot)}\u\[\e[0m\]@\h \[\e[01m\]\w\$(_PS1_git) \[\e[0m\]% "

나는 여전히 색상을 구성 할 수 있도록 노력하고 있지만 지금은 색상에 만족합니다.


현재 미친 ^[캐릭터와 쉬운 색상 전환 에 대한 수정 작업 중입니다. :)


Ctrl + [와 v가 동시에 아니라 Ctrl + v와 Ctrl + [가 뒤 따릅니다.
NieDzejkob


0

자일스 '답변을 추가, 더 나은 (제대로 묶여있어 제공되는 핸들 색상에 뭔가를 작성 \[하고 \]. 그것은 사건의 경우 별과 모든 경우를 처리하지 않습니다, 그러나 그것은 나를 PS1과 같은 구문 내 PS1L을 설정할 수 있습니다 (색이 지정되지 않은) 날짜를 PS1R로 사용합니다.

function title {
    case "$TERM" in
    xterm*|rxvt*)
        echo -en "\033]2;$1\007"
        ;;
    *)
        ;;
    esac
}

print_pre_prompt() {
    PS1R=$(date)
    PS1L_exp="${PS1L//\\u/$USER}"
    PS1L_exp="${PS1L_exp//\\h/$HOSTNAME}"
    SHORT_PWD=${PWD/$HOME/~}
    PS1L_exp="${PS1L_exp//\\w/$SHORT_PWD}"
    PS1L_clean="$(sed -r 's:\\\[([^\\]|\\[^]])*\\\]::g' <<<$PS1L_exp)"
    PS1L_exp=${PS1L_exp//\\\[/}
    PS1L_exp=${PS1L_exp//\\\]/}
    PS1L_exp=$(eval echo '"'$PS1L_exp'"')
    PS1L_clean=$(eval echo -e $PS1L_clean)
    title $PS1L_clean
    printf "%b%$(($COLUMNS-${#PS1L_clean}))b\n" "$PS1L_exp" "$PS1R"
}

여기 github에 있습니다 : dbarnett / dotfiles / right_prompt.sh . 내 .bashrc에서 다음과 같이 사용합니다.

source $HOME/dotfiles/right_prompt.sh
PS1L='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]'
PS1='\[\033[01;34m\]\w\[\033[00m\]\$ '
PROMPT_COMMAND=print_pre_prompt

참고 : PS1R 이후에도 줄 바꿈을 추가하여 시각적 차이는 없지만 명령 기록에서 특정 명령을 다시 스크롤하면 프롬프트가 깨지지 않는 것 같습니다.

나는 누군가 다른 사람이 이것을 향상시킬 수 있다고 확신하고, 특별한 경우를 일반화 할 수 있습니다.


0

여기에 기반 솔루션 PROMPT_COMMAND과는 tput:

function __prompt_command() {
  local EXIT="$?"             # This needs to be first
  history -a
  local COL=$(expr `tput cols` - 8)
    PS1="💻 \[$(tput setaf 196)\][\[$(tput setaf 21)\]\W\[$(tput setaf 196)\]]\[$(tput setaf 190)\]"
    local DATE=$(date "+%H:%M:%S")
  if [ $EXIT != 0 ]; then
    PS1+="\[$(tput setaf 196)\]\$"      # Add red if exit code non 0
    tput sc;tput cuu1; tput cuf $COL;echo "$(tput setaf 196)$DATE"; tput rc
  else
  PS1+="\[$(tput setaf 118)\]\$"
    tput sc;tput cuu1; tput cuf $COL;echo "$(tput setaf 118)$DATE"; tput rc
  fi
  PS1+="\[$(tput setaf 255)\] "
}
PROMPT_COMMAND="__prompt_command"

마법은 다음에 의해 수행됩니다.

tput sc;tput cuu1; tput cuf $COL;echo "$(tput setaf 196)$DATE"; tput rc

다음과 같이 분류됩니다.

tput sc                       # saved the cursor position
tput cuu1                     # up one line
tput cuf $COL                 # move $COL characters left
echo "$(tput setaf 196)$DATE" # set the colour and print the date
tput rc                       # restore the cursor position

PS1에서 tput\ [\]로 이스케이프되어 표시된 길이로 계산되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.