Сокращение подсказки Bash

Я только что перешел с tcsh на bash и, в частности, пропустил параметры запроса на сокращение каталога с помощью %c02 (с установленным также ellipsis).

Я вижу, что PROMPT_DIRTRIM делает почти все правильно (кроме многоточия, я думаю), но я только на bash 3 (на OS X). Я нашел этот рецепт в другом месте на SO, который сокращает общую длину, поэтому разбивает пути в середине каталогов, чего я не делал. не нравится.

Итак, я придумал это:

PROMPT_DIRTRIM=2   ## from bash4, but used here
dirtrim() 
{
    local NAME="$1" start= endelts=
    [[ "$NAME" =~ ^"$HOME"(/|$) ]] && NAME="~${NAME#$HOME}"  ## $HOME ==> ~
    IFS=/ read -ra elts <<< "$NAME";          ## split $PWD on "/"
    start=$((${#elts[@]}-${PROMPT_DIRTRIM}))  ## first element to retain
    if [ ${start} -gt 1 ]; then     
        for ((i=${start}; i<${#elts[@]}; i++)); do 
            endelts="${endelts}/${elts[$i]}"; ## concat together the trailing path
        done
        NAME="...${endelts}"
    fi
    echo "$NAME"    
}
PS1='\h:$(dirtrim "$PWD")\$ '

Оно работает:

blackat:~$ cd ~/Library/Application\ Support/Apple
blackat:.../Application Support/Apple$

Но я новичок в bash и недоволен явным циклом for (()); однако я не мог найти другого способа воссоединить последние записи разделенного массива elts таким образом, чтобы правильно обрабатывать пробелы в именах каталогов (например, используя ${elts[@]:${start}}). Любые подсказки, чтобы сделать это или другие улучшения?

(Кстати, я думаю, что это это вопрос по программированию, поскольку bash является языком программирования....)


person Andrew Jaffe    schedule 27.05.2016    source источник
comment
Баш — это язык программирования.   -  person Jonathan Leffler    schedule 28.05.2016
comment
@Jonathan Leffler: Согласен - это было в ответ на два голосования за закрытие!   -  person Andrew Jaffe    schedule 28.05.2016
comment
И я утверждаю, что вопросы о программировании Bash — это вопросы программирования, и поэтому они обсуждаются на Stack Overflow. Закрытие вопросов о программировании оболочки как не относящихся к теме раньше было серьезной проблемой; в эти дни я не вижу, чтобы это происходило так часто, но это может просто означать, что я скучаю по этому, и это происходит все время. FWIW: Мне тоже не нравятся длинные подсказки: я вообще не включаю путь в подсказку. На машине «сфинкс» мое приглашение — Sphinx JL: . С терминалом Mac вы можете указать путь в строке заголовка терминала («Свойства» -> «Окно» и найти раздел «Заголовок»).   -  person Jonathan Leffler    schedule 28.05.2016


Ответы (2)


Вы можете попробовать это:

if ((start > 1)); then
  name=$(IFS=/; echo .../"${elts[*]:start}")
  # If your terminal is correctly set up for unicode, you can save two character positions:
  # name=$(IFS=/; echo …/"${elts[*]:start}")
fi

Обратите внимание, что в bash в арифметическом контексте, который включает внутреннюю часть ((...)) и индексы массива, вы можете написать только имя переменной; сигилы не нужны.

Другой способ сделать это будет

if ((start > 1)); then
  printf -v name "/%s" "${elts[@]:start}"
  name=...$name
fi

Еще одно решение, использующее захваты регулярных выражений в массиве BASH_REMATCH вместо разделения и воссоединения строки:

dirtrim () { 
  local path="$1";
  [[ $path =~ ^"$HOME"(/.*)? ]] && path=~${BASH_REMATCH[1]};
  ((PROMPT_DIRTRIM)) &&
    [[ $path =~ ...*((/[^/]*){$PROMPT_DIRTRIM}) ]] &&
    path=…${BASH_REMATCH[1]};
  echo "$path"
}

Тест ((PROMPT_DIRTRIM)) не является полностью надежным из-за особенностей оценки bash в арифметическом контексте. Для распространения вы можете предпочесть что-то вроде [[ $PROMPT_DIRTRIM =~ ^[1-9][0-9]*$ ]]

person rici    schedule 27.05.2016
comment
1. Договорились о корпусе; Я получил NAMES из другого ответа. 2. Я имел в виду ((start>1)) -- если start==1 вы просто сохраните первую запись; 3. Я думаю, что вы имели в виду name=$(IFS=/; echo .../"${elts[*]:start}") (примечание: IFS=/ и отсутствует $) - person Andrew Jaffe; 28.05.2016
comment
@andrew: Первая запись массива bash имеет индекс 0. Вы правы насчет опечаток, я выбегал из двери, когда набирал это. Извините, и я исправил это сейчас. - person rici; 28.05.2016
comment
да, но нулевая запись - это ~ или null, поэтому мы действительно хотим сократить только тогда, когда start>1 - person Andrew Jaffe; 28.05.2016
comment
@AndrewJaffe: А, хорошая мысль. Нет смысла укорачивать, если не будет короче. Для вашего удовольствия я добавил решение с использованием регулярных выражений, которое полностью избегает разделения и объединения. - person rici; 28.05.2016

На самом деле это не ответ, но вы можете посмотреть, как mksh выполняет это:

PS1=${| local e=$? (( e )) && REPLY+="$e|" REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)} REPLY+=@${HOSTNAME%%.*}: local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~} local m=${%d} n p=...; (( m > 0 )) || m=${#d} (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p= REPLY+=$p$d return $e }

К сожалению, он использует некоторые расширения, которых, по-моему, нет в bash.

Кроме того, поскольку вы меняете оболочки... не думали ли вы об рыбе?

Он делает это из коробки, а затем некоторые.

person Geoff Nixon    schedule 27.05.2016