2013-11-13 2 views
15

Если выход команды не заканчивается с \n, появляется следующая подсказка, неуклюже, сразу же после этого:Настройки оболочка всегда печатать строки на новой строке, как Zsh

$ echo -n hai 
hai$ 

Я только что заметил, коллега которого оболочка (ЗШ, для чего это стоит) выполнено с возможностью печатать % (с фоновым и цветом переднего плана перевернутым для выразительности) с последующим \n в таких случаях:

$ echo -n hai 
hai% 
$ 

Я хотел бы сделать то же самое. Я использую Bash. Это возможно? Если да, то что бы я добавил к моему ~/.bashrc?


UPDATE

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

  • ESC[6n представляет собой последовательность интродьюсер управления для доступа к позиции курсора (http://en.wikipedia.org/wiki/ANSI_escape_code).

  • \e не является допустимым выражением ESC при использовании echo на OS X (https://superuser.com/q/33914/176942). Вместо этого можно использовать \033. (http://tldp.org/LDP/abs/html/internalvariables.html#IFSREF).

  • read -sdR выглядит как стенография для read -s -d -R, но на самом деле «R» не флаг, это значение опции -d (разделителей). Вместо этого я решил написать read -s -d R, чтобы избежать путаницы.

  • Конструкция с двойными скобками, ((...)), разрешает арифметическое расширение и оценку (http://tldp.org/LDP/abs/html/dblparens.html).

Вот соответствующий отрывок из моей .bashrc:

set_prompt() { 
    # CSI 6n reports the cursor position as ESC[n;mR, where n is the row 
    # and m is the column. Issue this control sequence and silently read 
    # the resulting report until reaching the "R". By setting IFS to ";" 
    # in conjunction with read's -a flag, fields are placed in an array. 
    local curpos 
    echo -en '\033[6n' 
    IFS=';' read -s -d R -a curpos 
    curpos[0]="${curpos[0]:2}" # strip leading ESC[ 
    ((curpos[1] > 1)) && echo -e '\033[7m%\033[0m' 

    # set PS1... 
} 

export PROMPT_COMMAND=set_prompt 

Примечание: curpos[0]="${curpos[0]:2}" линия не нужна. Я включил его, чтобы этот код можно было использовать в контексте, где строка также имеет значение.

+0

Почему бы не спросить его, как это делается. Скорее всего, это будет тот же самый фрагмент в вашем '~/.bashrc', что и его' ~/.zshrc'. Этот вопрос может быть лучше подходит для [Server Fault] (http://serverfault.com/), но где вы желая только добавлять строки без \ n перерывов? – MattSizzle

+0

Я спросил его, и мы посмотрели его ~/.zshrc, но не смогли найти код. Да, я хотел бы добавить только вывод, который не заканчивается на '\ n'. – davidchambers

+1

Это то, что я не смог найти вчера в Google, и, похоже, является zch-специфичным, поскольку у него есть много новой информации о обработке линии. Я собираюсь рассмотреть это позже сегодня вечером, поскольку я хочу знать, как сделать это сам сейчас. – MattSizzle

ответ

12

Маленькая хитрость с использованием PROMPT_COMMAND:

Значение переменной PROMPT_COMMAND проверяется непосредственно перед Bash каждого базового приглашения. Если значение PROMPT_COMMAND установлено и имеет ненулевое значение, то значение выполняется так же, как если бы оно было введено в командной строке.

Таким образом, если вы это в вашем .bashrc:

_my_prompt_command() { 
    local curpos 
    echo -en "\E[6n" 
    IFS=";" read -sdR -a curpos 
    ((curpos[1]!=1)) && echo -e '\E[1m\E[41m\E[33m%\E[0m' 
} 
PROMPT_COMMAND=_my_prompt_command 

вы будете очень хорошо. Не стесняйтесь использовать другие причудливые цвета в части echo "%". Вы можете даже поместить содержимое этого в переменную, чтобы вы могли изменить его на лету.

Хитрости: получить столбец курсора (с последующей echo -en "\E[6n" командой read) перед печатью строки и если это не 1, печатать % и символ новой строки.

Плюсы:

  • чистый Баш (без внешних команд),
  • нет Подоболочки,
  • оставляет свой PS1 все красивым и чистым: если вы хотите изменить свой PS1 иногда (я делаю это, когда Я работаю в глубоко вложенном каталоге - мне не нравятся подсказки, которые запускаются на несколько миль), это все равно будет работать.

Как tripleee комментариев, вы могли бы использовать stty вместо вторя жестко запрограммированную последовательность управления. Но это использует внешнюю команду и не является чистым bash. Адаптируйте к вашим потребностям.


Что касается вашей проблемы с некрасивыми кодов символов, которые получают случайным образом напечатанных: это может быть потому, что есть еще некоторые вещи в буфере терминала. Там может быть несколько исправлений:

  1. Выключите, а затем на echo терминала, используя stty.

    set_prompt() { 
        local curpos 
        stty -echo 
        echo -en '\033[6n' 
        IFS=';' read -d R -a curpos 
        stty echo 
        ((curpos[1] > 1)) && echo -e '\033[7m%\033[0m' 
    } 
    PROMPT_COMMAND=set_prompt 
    

    основное отличие состоит в том, что комбо echo/read был обернут stty -echo/stty echo, что, соответственно, отключает и позволяет вторя на терминале (именно поэтому -s вариант read теперь бесполезно). В этом случае вы не получите правильную позицию курсора, и это может привести к появлению странных сообщений об ошибке, или % не будет выводиться вообще.

  2. Явное ясно TTY буфер:

    set_prompt() { 
        local curpos 
        while read -t 0; do :; done 
        echo -en '\033[6n' 
        IFS=';' read -s -d R -a curpos 
        ((curpos[1] > 1)) && echo -e '\033[7m%\033[0m' 
    } 
    PROMPT_COMMAND=set_prompt 
    
  3. Просто сдавайтесь, если буфер терминала не может быть очищен:

    set_prompt() { 
        local curpos 
        if ! read -t 0; then 
         echo -en '\033[6n' 
         IFS=';' read -s -d R -a curpos 
         ((curpos[1] > 1)) && echo -e '\033[7m%\033[0m' 
        # else 
        #  here there was still stuff in the tty buffer, so I couldn't query the cursor position 
        fi 
    } 
    PROMPT_COMMAND=set_prompt 
    

В качестве примечания: вместо read в массиве curpos, вы можете напрямую получить положение курсора в переменных, например curx и cury:

IFS='[;' read -d R _ curx cury 

Если вам нужно только у-позицию cury:

IFS='[;' read -d R _ _ cury 
+1

Впечатляет! Это прекрасное решение. Последний вопрос: зачем цитировать имя функции, почему бы не просто 'PROMPT_COMMAND = _my_prompt_command' – janos

+0

@janos благодарит за ваш комментарий. Вы правы, цитаты бесполезны там, я их удалю. –

+0

Я полагаю, что вы могли бы получить некоторую переносимость, используя 'stty' вместо' echo' в жестко закодированную последовательность управления. – tripleee

1

если вы echo $PS1 вы увидите де текущий код вашего запроса, как это:
\[\e]0;\[email protected]\h: \w\a\]${debian_chroot:+($debian_chroot)}\[email protected]\h:\w\$

Теперь предварять его с \n, как это:

PS1="\n\[\e]0;\[email protected]\h: \w\a\]${debian_chroot:+($debian_chroot)}\[email protected]\h:\w\$"

теперь ваша подсказка будет всегда начните с новой строки.

+0

Это добавит лишний '\ n' в общий случай (когда вывод команды заканчивается на' \ n'). – davidchambers

+0

@ davidchambers Да :-) – thom

+0

Да, я думал сначала о PS1, но OP хочет добавить только тогда, когда предыдущий вывод не имел возврата/n. – MattSizzle

3

Благодаря Жиль на unix.stackexchange:

Вы можете сделать Баш отобразить его приглашение на следующую строку, если предыдущая команда оставила курсор где-то, кроме последнего края. Поместите это в .bashrc (изменение по GetFree предложения, по Dennis Williamson)

Из двух связанных ответов я дистиллированная это решение:

PS1='\[\e[7m%\e[m\]$(printf "%$((COLUMNS-1))s")\r$ ' 

Объяснение:

  • \[\e[7m%\e[m\] - знак обратного видео процента
  • printf "%$((COLUMNS-1))s" - COLUMNS-1 пробелы. Переменная COLUMNS сохраняет ширину вашего терминала, если установлены параметры checkwinsize. Поскольку printf находится в $() суб-оболочки, вместо печати на экран его выход будет добавлен к PS1
  • \r символ возврата каретки

Так, в основном, это % знак, длинная последовательность пробелов, за которым следует ключ возврата. Это работает, но, честно говоря, я не понимаю, почему это имеет желаемый эффект. В частности, почему это выглядит так, что добавляет разрыв строки только тогда, когда это необходимо, иначе лишний разрыв строки? Почему там нужны места?

+0

«Это не полностью касается вашего вопроса, так как я не знаю, как положить'% 'в конце строки, например' zsh'. - Ответ Денниса Уильямсона (к которому вы связались) делает это. – davidchambers

+1

работает, не вызывая прерывания строки - он пробегает правый край экрана, а затем выводит возврат каретки - не новую строку - для перемещения курсора в начало текущей строки. Если предыдущая строка заканчивалась где угодно, но в начале строки, то пробелы будут обертываться, и CR будет просто перейти к началу этой короткой строки. –

+0

@evilotto как насчет количества пробелов? Почему важно иметь точно «COLUMNS-1»? – janos

Смежные вопросы