Bash: пользовательский PS1 с хорошим рабочим каталогом

Я использую Ubuntu, и я устал от этих длинных запросов в bash, когда я работаю с некоторой глубокой иерархией каталогов. Итак, я хотел бы настроить мой PS1, чтобы сократить часть рабочего каталога следующим образом:

В настоящее время у меня есть:

[email protected]:~/workspace/projects/project1/folder1/test$

и хотел бы иметь:

[email protected]:~/workspace/.../folder1/test$

Усечение произойдет, если len ($ PWD) передает заданный порог. Я хочу всегда сохранить первый компонент пути и по крайней мере один последний компонент пути. Затем, как позволяет пространство, добавьте еще несколько элементов справа.

Это то, что у меня есть сейчас. Он работает, но: 1) не поддерживает компонент первого пути, 2) не рассматривает путь резания на границах:

pwd_length=14
pwd_symbol="..."
newPWD="${PWD/#$HOME/~}"

if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]
then
   newPWD="...$(echo -n $PWD | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")"
else
   newPWD="$(echo -n $PWD)"
fi

И результат:

[email protected]:...sth/folder1/sample$ 

Спасибо заранее!

Ответ 1

Рассмотрим этот script, используя awk вместо sed для вашего случая:

pwd_length=14
pwd_symbol="..."
newPWD="${PWD/#$HOME/~}"
if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]
then
   newPWD=$(echo -n $newPWD | awk -F '/' '{
   print $1 "/" $2 "/.../" $(NF-1) "/" $(NF)}')
fi
PS1='${newPWD}$ '

В вашем примере каталога ~/workspace/projects/project1/folder1/test он делает PS1 следующим: ~/workspace/.../folder1/test

UPDATE

Над решением будет установлено ваше приглашение, но, как вы отметили в своем комментарии, он не изменит PS1 динамически при смене каталога. Итак, вот решение, которое будет динамически устанавливать PS1 при изменении каталогов.

Поместите эти 2 строки в ваш .bashrc файл:

export MYPS='$(echo -n "${PWD/#$HOME/~}" | awk -F "/" '"'"'{
if (length($0) > 14) { if (NF>4) print $1 "/" $2 "/.../" $(NF-1) "/" $NF;
else if (NF>3) print $1 "/" $2 "/.../" $NF;
else print $1 "/.../" $NF; }
else print $0;}'"'"')'
PS1='$(eval "echo ${MYPS}")$ '

if (NF > 4 && length($0) > 14) условие в awk применит только специальную обработку, если ваш текущий каталог содержит более 3 каталогов. И если длина $PWD составляет более 14 символов, и она будет поддерживать PS1 как $PWD.

например: если текущий каталог ~/workspace/projects/project1$, тогда PS1 будет ~/workspace/projects/project1$

Эффект выше в .bashrc будет следующим на вашем PS1:

~$ cd ~/workspace/projects/project1/folder1/test
~/workspace/.../folder1/test$ cd ..
~/workspace/.../project1/folder1$ cd ..
~/workspace/.../project1$ cd ..
~/.../projects$ cd ..
~/workspace$ cd ..
~$

Обратите внимание, как меняется запрос при изменении каталогов. Дайте мне знать, если это не то, что вы хотели.

Ответ 2

Для людей, которые ищут гораздо более простое решение и не нуждаются в имени первого каталога в пути, Bash имеет встроенную поддержку для этого с помощью переменной PROMPT_DIRTRIM. Из документации:

PROMPT_DIRTRIM

Если установлено число, большее нуля, это значение используется как количество возвращаемых компонентов каталога, которые нужно сохранить при расширении приглашений строки \w и\W (см. Печать подсказки). Удаленные символы заменяются многоточием.

Например:

~$ mkdir -p a/b/c/d/e/f
~$ cd a/b/c/d/e/f
~/a/b/c/d/e/f$ export PROMPT_DIRTRIM=2
~/.../e/f$ PROMPT_DIRTRIM=3
~/.../d/e/f$ 

Даунсайд: это зависит от уровня каталога, а не от длины пути, который вам может не понадобиться.

Поверхность: Это очень просто. Просто добавьте export PROMPT_DIRTRIM=2 к вашему .bashrc.

Ответ 3

Это то, что я использую на основе решений от anubhava. Он устанавливает как приглашение, так и заголовок окна. Awk script является более читаемым, поэтому его можно легко настроить/настроить.

Он сложит путь, если он будет содержать более 16 символов и 4 уровня. Кроме того, он также укажет в... сколько каталогов было сложенным, так что вы получите представление о том, насколько глубоко путь, т.е.: ~/usr/..4../path2/path1 указывает, что 4 уровня были сфальцованы.

# define the awk script using heredoc notation for easy modification
MYPSDIR_AWK=$(cat << 'EOF'
BEGIN { FS = OFS = "/" }
{ 
   sub(ENVIRON["HOME"], "~");
   if (length($0) > 16 && NF > 4)
      print $1,$2,".." NF-4 "..",$(NF-1),$NF
   else
      print $0
}
EOF
)

# my replacement for \w prompt expansion
export MYPSDIR='$(echo -n "$PWD" | awk "$MYPSDIR_AWK")'

# the fancy colorized prompt: [0 [email protected] ~]$
# return code is in green, [email protected] is in bold/white
export PS1='[\[\033[1;32m\]$?\[\033[0;0m\] \[\033[0;1m\]\[email protected]\h\[\033[0;0m\] $(eval "echo ${MYPSDIR}")]$ '

# set x/ssh window title as well
export PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*} $(eval "echo ${MYPSDIR}")\007"'

Вот как это выглядит в действии. Зеленый 0 - это код возврата последней команды:

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

Ответ 4

echo -n $PWD | sed -re "s|(~?/[^/]*/).*(.{$pwd_length})|\1...\2|"

sed с -r только для удобства, позволяет опустить обратную косую черту перед скобками и "|" как разделитель только для удобства - потому что мы хотим использовать косую черту внутри команды. Я думаю, ваш дом будет отображаться как ~, так что ~/foo/bar/baz/должен закончиться в ~/foo/.../baz и /foo/bar/baz/as/foo/.../baz/.

Итак, мы берем опцию ~, за которой следуют слэш, имя, слэш как \1, затем что-то, а затем остальные как\2.

Ответ 5

Другой подход, по-прежнему использующий sed и awk для генерации запроса. Это преобразует ваш каталог $HOME в ~, покажет вам ваш корневой каталог, ваш самый низкий уровень (текущий каталог) и его родительский элемент, разделенный .. для каждого каталога между ними.

Внутри вашего .bashrc (или .bash_profile в OS X):

function generate_pwd {
  pwd | sed s.$HOME.~.g | awk -F"/" '
  BEGIN { ORS="/" }
  END {
  for (i=1; i<= NF; i++) {
      if ((i == 1 && $1 != "") || i == NF-1 || i == NF) {
        print $i
      }
      else if (i == 1 && $1 == "") {
        print "/"$2
        i++
      }
      else {
        print ".."
      }
    }
  }'
}
export PS1="\$(generate_pwd) -> "

script использует awk, встроенный в переменную NF (количество полей) и позиционные переменные ($1, $2 ...), для печати каждого поля (имя каталога), разделенного переменной ORS (разделитель выходной записи). Он сворачивает внутренние каталоги в .. в приглашении.

Пример использования:

~/ -> cd Documents/
~/Documents/ -> cd scripts/
~/Documents/scripts/ -> cd test1/
~/../scripts/test1/ -> cd test2
~/../../test1/test2/ -> pwd
/Users/Brandon/Documents/scripts/test1/test2
~/../../test1/test2/ -> cd test3/
~/../../../test2/test3/ -> cd test4/
~/../../../../test3/test4/ -> pwd
/Users/Brandon/Documents/scripts/test1/test2/test3/test4
~/../../../../test3/test4/ -> cd /usr/
/usr/ -> cd local/
/usr/local/ -> cd etc/
/usr/local/etc/ -> cd openssl/
/usr/../etc/openssl/ -> cd private/
/usr/../../openssl/private/ ->

Ответ 6

Помимо решения bash -builtin с помощью PROMPT_DIRTRIM, вы можете попробовать $(pwd | tail -c16), который немного проще, чем большинство других ответов, но просто дает последние 16 символов текущего каталога. Конечно, замените 16 на любое количество, которое вы хотите.

Ответ 7

Почему бы просто не использовать ${string:position:length}? Вы можете сделать ${string:-$max_chars}, чтобы иметь последний ${max_chars} строки.

обратите внимание на отрицательное значение

Ответ 8

Не так сильно отличается от предыдущих решений. Однако, может быть, немного читаем/редактируем. Тем не менее, нет решения для границы имен папок, но основное внимание уделяется длине запроса.

### SET MY PROMPT ###
if [ -n "$PS1" ]; then
    # A temporary variable to contain our prompt command
    NEW_PROMPT_COMMAND='
        pwd_short=${PWD/#$HOME/\~};
        if [ ${#pwd_short} -gt 53 ]; then
            TRIMMED_PWD=${pwd_short: 0: 25}...${pwd_short: -25}
        else
            TRIMMED_PWD=${pwd_short}
        fi
    '

    # If there an existing prompt command, let not 
    # clobber it
    if [ -n "$PROMPT_COMMAND" ]; then
        PROMPT_COMMAND="$PROMPT_COMMAND;$NEW_PROMPT_COMMAND"
    else
        PROMPT_COMMAND="$NEW_PROMPT_COMMAND"
    fi

    # We're done with our temporary variable
    unset NEW_PROMPT_COMMAND

    # Set PS1 with our new variable
    # \h - hostname, \u - username
    PS1='\[email protected]\h: $TRIMMED_PWD\$ '
fi

добавлен в файл .bashrc. Все части подсказки обновляются должным образом. Первая часть сокращается, если вы находитесь в своем домашнем каталоге. <Б > Пример:

user @computer: ~/misc/projs/solardrivers... src/com/mycompany/обрабатывает $