Komut satırının sağa hizalı kısmı


27

Birisinin terminal penceresindeki sağa hizalanmış isteminin bir kısmını gördüğümden ve gerçek imlecin ikinci bir satırda başladığından eminim. PS1'de ikinci satırı "\ n" ile başarabileceğimi biliyorum, ancak bir kısmının sağa nasıl hizalanacağını çözemiyorum. Gördüğüm şey, iki dizi arasına boşluk eklenmiş miydi?

Yanıtlar:


17

İstemi görüntülemeden önce ilk satırı görüntüleyerek istediğiniz şeyi kolayca yapabilirsiniz. Örneğin, aşağıdakiler \wilk satırın solunda ve ilk satırın \u@\hsağında bir satır görüntüler. Bu kullanır $COLUMNSterminal ve genişliğini içerir değişken $PROMPT_COMMANDhızlı darbe görüntülenmesi için değerlendirilir parametresi.

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
Renkli bir sol bilgi istemeniz durumunda işlerin daha karmaşık hale geldiğini unutmayın; çünkü yazdırılmayan karakterler, dize uzunluğunun görüntülenen karakter sayısıyla aynı olmadığı anlamına gelir.
Mu Mind

1
Hem bu hem de en yüksek oyu alan cevap varsa .inputrc, doğru çalışmaz set show-mode-in-prompt on. Hem olmayan prinable uzunluğunu hesaplar değil ANSI CSI kodları ve düzgün bir şekilde bunları içine yoktur \[ve \]@Mu Zihin tarafından belirtildiği gibi. Çözünürlük için bu cevaba bakınız .
Tom Hale

26

Burada bulduğum bilgilere dayanarak, renk desteği de dahil olmak üzere sağa veya sola değişken uzunluktaki içeriği sağa çekerken sağa hizalamak için daha basit bir çözüm keşfedebildim. Rahatınız için buraya eklendi ...

Renkler hakkında not:\033 kaçışın alternatifler lehine kullanılması, \[\]gruplama yapılmaksızın en uyumlu ve tavsiye edilen kanıtlar.

İşin püf noktası ilk önce sağ tarafı yazmak, sonra \rsatırın başlangıcına dönmek için satırbaşı ( ) işlevini kullanmak ve bunun üzerine sol taraftaki içeriğin üzerine yazmaya devam etmek:

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

tput colsMac OS X'te kullanıyorum terminalimden / konsolun genişliğinden var terminfovarlığım $COLUMNSdoldurulmadığından alınıyor envancak yerine " *" değerini yerine %*s" ${COLUMNS}" veya yerine başka bir değer girerek değiştirebilirsiniz.

Bir sonraki örnek, $RANDOMfarklı uzunluktaki içerik üretmek için kullanır , renkler içerir ve uygulamayı yeniden kullanılabilir işlevlere yeniden yansıtmak için işlevleri nasıl çıkarabileceğinizi gösterir.

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

Yana printfbiz renkleri oluşturmak için gereken karakter miktarı telafi etmek gerek karakterlerin # olarak string uzunluğunu varsayar olmayan tazminatsız ANSI karakterleri baskılı çünkü, her zaman kısa ekranın sonu bulabilirsiniz. Renk için gereken karakterler sabit kalır ve ayrıca printf'nin uzunluktaki değişikliği de hesaba $RANDOMkatarsınız;

Bu (yani. Özel bash istemi çıkış sıralarını durum böyle değil \u, \w, \h, \tistemi görüntülendiğinde Printf dize kılmış sonra bash sadece çevirecektir çünkü bunlar sadece 2 uzunluğuna kaydeder gibi) olsa. Bu, sol tarafı etkilemez, ancak sağda olmalarını önlemek için en iyisidir.

Sonuçta oluşturulan içerik olsa da sabit uzunlukta kalırsa. Zaman olduğu gibi \ther zaman 24 defa karakterler (8) aynı miktarda hale getirecek seçeneği. Bu durumlarda, yazdırıldığında 8 karakterle sonuçlanan 2 karakter arasındaki farkı karşılamak için gereken telafiyi hesaba katmamız gerekir.

Akılda tutulması gereken \\\bazı kaçış dizileri üçlü kaçış gerekebileceğini unutmayın, aksi halde dizeleri anlam ifade eder. Aşağıdaki örnekte olduğu gibi, geçerli çalışma dizini kaçış \wbaşka bir anlam ifade etmiyor, bu yüzden beklendiği gibi çalışıyor, ancak \tsekme karakteri anlamına gelen süre , ilk önce üçlü çıkış yapmadan beklendiği gibi çalışmaz.

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

Njoy!


8

Kullanımı printfile $COLUMNSolduğu gibi, gerçekten iyi bir şey çalıştı:

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

Doğru, benim için mükemmel bir şekilde haklı çıkardı.


6

Aşağıdakiler, terminalin RHS'sinde geçerli tarih ve saati KIRMIZI olarak koyacaktır.

# 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}"

Avantajları:

  • RHS isteminde renkler ve ANSI CSI kodları ile doğru çalışıyor
  • Alt işlem yok. shellchecktemiz.
  • Doğru olmadığını Works .inputrcsahiptir set show-mode-in-prompt on.
  • Doğru olmayan istemi uzunlukta veren karakterleri kapsüller \[ve \]istemi girilen metin düzenlerken garip yeniden yazdırmak için istemi neden olmaz böylece.

Not : Siz herhangi bir renk dizileri sağlamak gerekir $PS1bu kodundan önce düzgün içine alınır exeucted edilir \[ve \]bunlardan hiçbir yuvalama yoktur ve bu.


teoride bu yaklaşımı sevsem de pratikte kutudan çıkmıyor (ubuntu 18.04, GNU bash 4.4.19): kodu doğrudan .bashrc'ye eklemek ilk önce bash: local: can only be used in a functiondüzeltmek için önemsiz olan hatayı veriyor ve Ondan sonra, hiçbir şey göstermiyor çünkü COLUMNStanımlı değil: değiştirilmek zorunda $(tput cols). snippet farklı bir dosyaya kaydedildiğinde ve sonra kaynaklandığında da aynı sonuç .bashrc.
Polentino

1
@Polentino teşekkürler. tput colsEğer $COLUMNSayarlanmamışsa çalıştırılacak kodu güncelledim . Ve evet, bu kod bir fonksiyonun içinde olmalı. Ben PROMPT_COMMAND='_prompt_bash_set'işlevi kullanır ve adlandırırım _prompt_bash_set.
Tom Hale,

2

Sadece benimkini buraya atacağımı düşündüm. Neredeyse tam olarak GRML zsh istemiyle aynıdır (zsh güncellemeleri hariç, yeni satırlarda ve arka alanlarda biraz daha iyidir - bu bashta çoğaltılması imkansızdır ... en azından zamanda bu noktada çok zor).

Bunun için iyi bir üç gün geçirdim (sadece ark çalıştıran bir dizüstü bilgisayarda test edilmiş), işte bir ekran görüntüsü ve sonra ~ / .bashrc :)

bash isteminin ekran görüntüsü

uyarı - biraz çılgınca

önemli bir yana - her biri ^[(örneğin ^[[34m) gerçekten kaçış karakteridir (char)27. Bunu eklemek için bildiğim tek yolu girmektir ctrl+ ( [v) (yani hem vurmak [ve vsüre ctrlaşağı tutulur.

# 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\]% "

Renkleri yapılandırılabilir hale getirmeye çalışıyorum, ancak şu anda olduğu gibi renkler ile mutluyum.


Şu anda çılgın ^[karakter ve kolay renk değiştirme için bir düzeltme üzerinde çalışıyor :)


Ctrl + [ve v aynı anda değil, Ctrl + v ve ardından Ctrl + [.
NieDzejkob


0

Giles'in cevabını ekleyerek, renkleri daha iyi kullanabilmeleri için bir şeyler yazdım (doğru şekilde yerleştirilmeleri koşuluyla \[ve \]. ve (renksiz) tarihi PS1R olarak kullanır.

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"
}

İşte github'da : dbarnett / dotfiles / right_prompt.sh . Bunu benim .bashrc'imde böyle kullanırım:

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

Not: Ayrıca PS1R'den sonra görsel bir fark yaratmayan yeni bir satır ekledim, ancak komut geçmişinizde belirli komutları geri kaydırırsanız istemin karışmasını önlüyor.

Başka birinin bu konuda gelişebileceğine eminim ve belki de özel durumların bir kısmını genelleştirebilirim.


0

İşte PROMPT_COMMANDve dayalı bir çözüm 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"

Sihir tarafından gerçekleştirilir:

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

Hangi tarafından bozuldu:

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'de tput\ [\] ile kaçılır, böylece görüntülenen uzunlukta sayılmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.