Компактна команда bash під час використання каталогу / імені файлів


16

У системі з Ubuntu 14.04 і bash, я PS1змінна, що закінчується таким вмістом:

\u@\h:\w\$

так що підказка відображається як

user@machinename:/home/mydirectory$

Однак іноді поточний каталог має довге ім’я, або він знаходиться всередині каталогів з довгими іменами, так що підказка виглядає як

user@machinename:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name$

Це заповнить рядок у терміналі, і курсор перейде до іншого рядка, який дратує.

Натомість я хотів би отримати щось подібне

user@machinename:/home/mydirectory1/...another_long_name$

Чи є спосіб визначити PS1змінну на "обгортання" та "компактність" імені каталогу, щоб ніколи не перевищувати певну кількість символів, отримуючи коротший запит?


1
На щастя, я пам’ятаю, де я читав, як налаштувати підказку для оболонки: tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html Дякую Джилсу Орру , автору Bash Prompt HOWTO та людям, які сприяли цьому.
1616 року

Дивіться також unix.stackexchange.com/a/216871/117549 (на основі ksh, але схожа ідея)
Jeff Schaller

Відповіді:


16

Перш за все, ви можете просто хочете змінити \wз \W. Таким чином, друкується лише ім'я поточного каталогу, а не весь його шлях:

terdon@oregano:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name $ PS1="\u@\h:\W \$ "
terdon@oregano:my_actual_directory_with_another_long_name $ 

Це може все-таки бути недостатньою, якщо ім'я каталогів занадто довге. У цьому випадку ви можете використовувати PROMPT_COMMANDзмінну для цього. Це спеціальна змінна bash, значення якої виконується як команда перед тим, як буде показано кожен запит. Отже, якщо ви встановите цю функцію, яка встановлює бажану підказку на основі довжини шляху поточного каталогу, ви можете отримати ефект, який ви шукаєте. Наприклад, додайте ці рядки до своїх ~/.bashrc:

get_PS1(){
        limit=${1:-20}
        if [[ "${#PWD}" -gt "$limit" ]]; then
                ## Take the first 5 characters of the path
                left="${PWD:0:5}"
                ## ${#PWD} is the length of $PWD. Get the last $limit
                ##  characters of $PWD.
                right="${PWD:$((${#PWD}-$limit)):${#PWD}}"
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] ${left}...${right} \$\[\033[00m\] "
        else
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] "
        fi


}
PROMPT_COMMAND=get_PS1

Ефект виглядає приблизно так:

terdon@oregano ~ $ cd /home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name
terdon@oregano /home...th_another_long_name $ 

10

Додавання повернення символів - це моє основне рішення для цього

Тож моя підказка (у якої теж є інші речі, що робить її ще довшою) виглядає приблизно так:

введіть тут опис зображення

Ви помітите, що $ повертається як новий рядок

Я досягаю цього за допомогою

HOST='\[\033[02;36m\]\h'; HOST=' '$HOST
TIME='\[\033[01;31m\]\t \[\033[01;32m\]'
LOCATION=' \[\033[01;34m\]`pwd | sed "s#\(/[^/]\{1,\}/[^/]\{1,\}/[^/]\{1,\}/\).*\(/[^/]\{1,\}/[^/]\{1,\}\)/\{0,1\}#\1_\2#g"`'
PS1=$TIME$USER$HOST$LOCATION'\n\$ '

Зауважте, що, хоч у окремому рядку, дуже довгі дерева каталогів, такі як

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails скорочуються до

/home/durrantm/Dropbox/_/code/ruby__rails

тобто "топ-3 каталоги / _ / нижній два каталоги", що, як правило, мене хвилює

Це дозволить гарантувати, що рядок ніколи не буде занадто довгою через довжину дерева каталогів. Якщо ви завжди хочете, щоб повне дерево каталогів просто відрегулюйте LOCATION, тобто

LOCATION=' \[\033[01;34m\]`pwd`'

Детальніше про колір на unix.stackexchange.com/q/124407/10043
Michael Durrant

1
Де фактично міститься ваш підказки $ ? (Дивіться це .)
G-Man каже: "Відновіть Моніку"

Наприкінці додано \ $, дякую. це тому, що зазвичай я також показую свою гіт-гіт, але це тут занадто багато деталей
Michael Durrant

1
Що? Немає нового рядка? Немає SGR0?
G-Man каже: "Відновіть Моніку"

Додано linefeed
Майкл Дюррант

3

Створено ~ / .bash_prompt:

maxlen=36
# set leftlen to zero for printing just the right part of the path
leftlen=19
shortened="..."
# Default PWD
nPWD=${PWD}
if [ ${#nPWD} -gt $maxlen ]; then
  offset=$(( ${#nPWD} - $maxlen + $leftlen ))
  nPWD="${nPWD:0:$leftlen}${shortened}${nPWD:$offset:$maxlen}"
else
  nPWD='\w'
fi
echo "\u@\h:$nPWD\$ "

Додано до мого ~ / .bash_profile:

function prompt_command {
  export PS1=$(~/.bash_prompt)
}
export PROMPT_COMMAND=prompt_command

Вихід:

user@machinename:/home/mydirectory1/...another_long_name$

1

Не рішення для скорочення довгих шляхів, але зручний спосіб отримати кращий огляд, зберігаючи всю інформацію про шлях, - додавання нового рядка перед останнім символом. Таким чином курсор запускається завжди в одному стовпчику, навіть якщо шлях достатньо довгий, щоб загорнутись, але вікно (и) консолі повинно бути досить високим, щоб не швидко прокручувати попередні рядки. Я видалив кольорові коди для більшої чіткості:

murphy@seasonsend:~
$ echo $PS1
\u@\h:\w\n\$
murphy@seasonsend:~
$ 

1

Я використовую це, він загортається на кілька ліній і відступів по довжині, user@hostтак що він припускає, що струм PS1ефективно ' \u@\h:\w$'. Він не обрізає шлях, і він адаптується до поточної ширини терміналу. Він розбиває лише шлях /, тому не елегантно має справу з дійсно довгими каталогами (але він зберігає простір для вибору / копіювання). Це гарантує, що у вас завжди є принаймні 20 символьних просторів для введення.

readonly _PS1="${PS1}" 2>/dev/null

function myprompt()
{
    local IFS
    local nn nb pbits xpwd="" ww=60 len=0 pp='\\w\$ '
    local indent uh="${LOGNAME}@${HOSTNAME//.*/}"

    test -n "$COLUMNS" && let ww=$COLUMNS-20  # may be unset at startup

    PS1="${_PS1}"
    if [ ${#PWD} -ge $ww ]; then
        printf -v indent "%${#uh}s%s" " " "> "  # indent strlen(user@host)

        IFS=/ pbits=( $PWD ); unset IFS
        nb=${#pbits[*]}
        for ((nn=1; nn<nb; nn++)) {
            if [ $(( $len + 1 + ${#pbits[$nn]} )) -gt $ww ]; then
                xpwd="${xpwd}/...\n${indent}..."
                len=0
            fi
            xpwd="${xpwd}/${pbits[$nn]}"
            let len=len+1+${#pbits[$nn]}
        }
        # add another newline+indent if the input space is too tight
        if (( ( ${#uh} + len ) > ww )); then
            printf -v xpwd "${xpwd}\n%${#uh}s" " " 
        fi 
        PS1="${PS1/$pp/$xpwd}$ "    
    fi
}
PROMPT_COMMAND=myprompt

Це працює, виймаючи магію \w(відповідає лише \w$для цього) PS1і замінюючи її $PWD, а потім загортаючи її як звичайний рядок символів. Він PS1щоразу перераховує початкове значення, яке зберігається _PS1, це означає, що «невидимі» втечі також зберігаються, моя повна оригінальна рядок підказок для xtermі жирного підказу:

PS1="\[\033]0;\u@\h:\w\007\]\[$(tput bold)\]\u@\h\[$(tput sgr0)\]:\w$ "

І кінцевий результат у терміналі 80 стовпців:

mr@onomatopoeia:~$ cd /usr/src/linux/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace
mr@onomatopoeia:/usr/src/linux/tools/perf/scripts/perl/Perf-Trace-Util/lib/...
               > .../Perf/Trace$ _

Це працює з bash-3.2, як printf -v varце використовується. Через різні складності знадобиться певна корекція для інших варіацій PS1.

(Шлях у рядку заголовка xterm не є ні загорнутим, ні скороченим, що можна зробити, включивши тут один із інших відповідей у ​​вищевказану функцію.)


0

Як альтернатива, у своєму .zshrc я скорочую першу букву кожного каталогу, якщо ширина пікселя перевищує певну ширину:

user@machinename:/home/mydirectory1/second_directory
user@machinename:/home/mydirectory1/second_directory/my_actual_directory

стає:

user@machinename:/h/mydirectory1/second_directory
user@machinename:/h/m/s/my_actual_directory

Ось функція zsh для цього:

     # get the path
     t=`print -P "%m:%~"`;
     t=`echo $t | sed -r 's/([^:])[^:]*([0-9][0-9]):|([^:])[^:]*([^:]):/\1\2\3\4:/'`;
     oldlen=-1;

     # create 4 buckets of letters by their widths
     t1="${t//[^ijlIFT]}";
     t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
     t3="${t//[^ABEKPSVXYCDHNRUw]}";
     t4="${t//[^GoQMmW]}";

     # keep abbreviating parent directories in the path until under 456 pixels
     while (( ( ( ${#t1} * 150 ) + ( ${#t2} * 178 ) + ( ${#t3} * 190 ) + ( ${#t4} * 201 ) ) > 4560 && ${#t}!=oldlen)) {
       oldlen=${#t};
       t=`echo $t | sed 's/\/\(.\)[^\/][^\/]*\//\/\1\//'`;
       t1="${t//[^ijlIFT]}";
       t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
       t3="${t//[^ABEKPSVXYCDHNRUw]}";
       t4="${t//[^GoQMmW]}";
     };

     PS1=$t

Я фактично використовую це для оновлення заголовка терміналу, так що за допомогою декількох вкладок я можу постійно розуміти, яка вкладка, яка. Повний .zshrc для цього є тут .

Це дуже зручно, оскільки він зберігає контекст, а zsh дозволяє швидко вкладати каталог у тому ж форматі. (наприклад, введення cd /h/m/s/<tab>автоматично завершиться cd /home/mydirectory1/second_directory)


Як це стосується питання поставленого ОП про те, як визначити рядок PS1?
Антон

$ T відредагований для наочності, $ t стає PS1
Річард

0

Спробуйте скористатися цим сценарієм Python . Він вирізає окремі розділи назви шляху, точно так, як ви хотіли у своєму запитанні. Він також використовує еліпсис unicode, який займає лише один стовпчик замість трьох.

Приклад виводу для вашого шляху (якщо вам задано обмеження в 30 знаків):

/home/mydir…/second…/my_actua

Варто зазначити, що це рішення правильно обробляє Unicode в іменах каталогу за допомогою wcswidth . ${#PWD}, які використовували інші відповіді, буде неправильно оцінювати візуальну ширину будь-якого шляху, що містить символи UTF-8.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.