Проблема с кодом: укорочение пути подсказки Bash

Я реализовал быстрое сокращение пути для включения bash в переменную среды PS1, которая сокращает рабочий каталог до чего-то более компактного, но все же описательного. Мне любопытно, какие еще идеи могут существовать.

Вот проблема:

Создайте функцию bash _dir_chomp , которая может быть включена в PS1 следующим образом (разрывы строк вставлены для удобства чтения):

PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] $(
  _dir_chomp "$(pwd)" 20
)\[\033[01;37m\]$(parse_git_branch)\[\033[01;34m\] \$\[\033[00m\] '

с параметром «20» для максимальной длины в качестве мягкого ограничения. Вот примеры:

  1. / usr / portage / media-plugins / banshee-community-extensions / files становится / u / p / m / b / files
  2. / home / user1 / media / video / music / live-sets становится ~ / m / v / m / live-sets (обратите внимание на символ ~ как замену $ HOME)
  3. / home / user2 / media НЕ изменяется (предел в 20 символов не превышен)
  4. / home / user1 / this-is-is-очень-long-path-name-with-than-20-chars становится ~ / this-is-is-очень-long-path-name-with-more-than-20-chars (последний компонент остается не сокращенным: мягкий предел)
  5. / home / user1 / src становится ~ / src ($ HOME всегда сокращается)
  6. /home/user1/.kde4/share/config/kresources становится ~ / .k / s / c / kresources (обратите внимание, что точка префикса сохраняется)

Текущий пользователь - user1.

Разрешено вызывать внешних интерпретаторов, например awk , perl , ruby ​​, python , но не скомпилированные программы на Си или аналогичные. Другими словами: внешние исходные файлы не допускаются, код должен быть встроенным. Кратчайшая версия выигрывает. Длина тела функции bash (и вызываемых подфункций) означает:

_sub_helper() {
  # this counts
}
_dir_chomp() {
  # these characters count (between { and })
  _sub_helper "foobar" # _sub_helper body counts, too
}
21
задан 2 revs 17 August 2010 в 07:24
поделиться

3 ответа

Pure Bash:

_dir_chomp () {
    local IFS=/ c=1 n d
    local p=(${1/#$HOME/\~}) r=${p[*]}
    local s=${#r}
    while ((s>$2&&c<${#p[*]}-1))
    do
        d=${p[c]}
        n=1;[[ $d = .* ]]&&n=2
        ((s-=${#d}-n))
        p[c++]=${d:0:n}
    done
    echo "${p[*]}"
}

В целях тестирования я предполагаю, что вопрос означает, что текущий пользователь - «user1».

Примечание: Bash 4 имеет переменную PROMPT_DIRTRIM , которая сокращает escape-последовательность \ w в PS1 , сохраняя количество подкаталогов в соответствии с ее значением и заменив остальные на ...

/$ PROMPT_DIRTRIM=2
/$ echo $PS1
\w\$
/$ pwd
/
/$ cd /usr/share/doc/bash
.../doc/bash$
12
ответ дан 29 November 2019 в 21:54
поделиться

Этот ответ примерно на 20 символов короче другого моего ответа:

_dir_chomp () {
    local p=${1/#$HOME/\~} b s
    s=${#p}
    while [[ $p != "${p//\/}" ]]&&(($s>$2))
    do
        p=${p#/}
        [[ $p =~ \.?. ]]
        b=$b/${BASH_REMATCH[0]}
        p=${p#*/}
        ((s=${#b}+${#p}))
    done
    echo ${b/\/~/\~}${b+/}$p
}
8
ответ дан 29 November 2019 в 21:54
поделиться

Это было мое собственное решение, когда у меня возникла идея для этой задачи. Вдохновением послужил Блог Джолексы.

Итак, вот она, реализация на рубине в удобочитаемой форме:

a = ARGV[1].gsub(%r{^#{ENV['HOME']}}, "~")
b, a = a, a.gsub(%r{/(\.?[^/.])[^/]+(/.*)}, '/\1\2') while
  (a.length > ARGV[2].to_i) && (b != a)
print a

И фактическая однострочная реализация в функции bash:

_dir_chomp() {
  ruby -e'a="'$1'".gsub(%r{^'$HOME'},"~");b,a=a,a.gsub(%r{/(\.?[^/.])[^/]+(/.*)},"/\\1\\2")while(a.length>'$2')&&(b!=a);print a'
}
1
ответ дан 29 November 2019 в 21:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: