Терминальная подсказка неправильно упакована

172

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

username@someserver ~/somepath $ ssh -i /path/to/private/key
myusername@something.someserver.com

Команда должна отображаться в две строки. Вместо этого он часто оборачивается и начинает писать поверх моей подсказки, примерно так:

myreallylongusername@something.somelongserver.comh -i /path/to/private/key

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

Дополнительное веселье происходит, когда я Upк предыдущей команде. Я пробовал это и в терминале gnome, и в терминаторе, и на i3 и Cinnamon. Кто-то предположил, что это была моя подсказка, поэтому вот что:

\[\033[01;32m\]\u:\[\033[01;34m\] \W\033[01;34m \$\[\033[00m\]

Ctrll, resetи clearвсе делают то, что говорят, но когда я набираю команду обратно или происходит Upто же самое.

Я проверил и checkwinsizeвключен в Bash. Это происходит в 80x24 и других размерах окна.

Это то, с чем я учусь жить? Есть ли какая-то магия, которую я должен знать? Я согласился только на использование очень короткого приглашения, но это не решает проблему.

Muricula
источник
1
Так что использование команды env -i bash --norcисправляет это. $ COLUMNS и $ LINES совпадают. Значит ли это, что с моим .bashrc что-то смешное?
Muricula
Поэтому я закомментировал свой .bashrc и в итоге выделил свою подсказку как проблемную часть, в частности, синтаксис окраски. Что не так с PS1 выше?
Muricula
1
\[\033[01;32m\]\u: \[\033[01;34m\]\W \[\033[01;34m\] \$ \[\033[0m\]кажется, избегает странностей в поведении - но не знаю, уважает ли оно ваше первоначальное приглашение полностью ...
1
Согласно этому ответу на serverfault , используйтеtput smam
Samveen

Ответы:

189

Непечатаемые последовательности должны быть заключены в \[и\] . Глядя на ваш PS1, у него есть нераскрытая последовательность после \W. Но вторая запись является избыточной, а также повторяет предыдущее утверждение «1; 34» .

\[\033[01;32m\]\u:\[\033[01;34m\] \W\033[01;34m \$\[\033[00m\]
                  |_____________|               |_|
                         |                       |
                         +--- Let this apply to this as well.

Как таковой, он должен иметь предназначенную окраску:

\[\033[1;32m\]\u:\[\033[1;34m\] \W \$\[\033[0m\]
                               |_____|
                                  |
                                  +---- Bold blue.

Сохраняя «оригинал», это также должно работать:

\[\033[1;32m\]\u:\[\033[1;34m\] \W\[\033[1;34m\] \$\[\033[0m\]
                                  |_|         |_|
                                   |           |
                                   +-----------+-- Enclose in \[ \]

Редактировать:

Причиной такого поведения является то, что bashсчитает, что подсказка длиннее, чем на самом деле. В качестве простого примера, если использовать один:

PS1="\033[0;34m$"
       1 2345678

Предполагается, что подсказка состоит из 8 символов, а не 1. Таким образом, если окно терминала состоит из 20 столбцов, то после ввода 12 символов оно считается 20 и переворачивается. Это также очевидно, если затем попытаться сделать возврат или Ctrl+u. Он останавливается на колонке 9.

Однако он также не начинает новую строку, если только она не находится в последнем столбце, в результате первая строка перезаписывается.

Если вы продолжаете печатать, строка должна переноситься на следующую строку после 32 символов.

Runium
источник
Если у вас - или у кого-то - есть объяснение относительно того, что именно в исходной последовательности заставило линию повториться над собой, мне было бы интересно узнать это. Также +1 за то, как вы показали это визуально.
1
@lightÉ: Не смотрел на источник, но добавил обновление с примечанием о поведении из наблюдения.
Runium
Если у вас возникнут какие-либо проблемы, вы можете использовать этот сайт для создания нового - bashrcgenerator.com
divinedragon
Это потрясающе, спасибо @Runium - не могли бы вы рассказать, откуда вы это узнали? Я хотел бы найти документацию по этому вопросу.
nycynik
2
@nycynik: Наблюдение. Я думаю, что ближе всего к документации по этому является исходный код ...
Runium
84

В основном это связано с тем, что размер окна, принятый терминалом, не совпадает с фактическим размером окна. Если вы используете Bash, вы можете попробовать это.

$ shopt checkwinsize

Если вы не получите

checkwinsize    on

Затем активируйте его с помощью

$ shopt -s checkwinsize

Затем просто попробуйте запустить другую команду (например ls) или изменить размер окна один раз, вышеописанное работает для меня каждый раз.

В частности, для систем Redhat проблема часто возникает из-за неправильной настройки, ~/.bashrcчтобы не вызывать /etc/bashrc. Обычно bash загружает ~/.bashrcожидаемый вызов /etc/bashrc, который по умолчанию содержит shopt -s checkwinsize.

saketrp
источник
У него была та же проблема с OS X, очевидно, если вы вызываете «login» для запуска терминала, он запускает bash так, что читает / etc / bashrc, но если вы просто вызываете напрямую bash, ~ / .bashrc не Исходные вещи по умолчанию, так что вы получите странный эффект упаковки. Спасибо!
rogerdpack
Это сработало и для меня. Цвета не были включены на этом конкретном сервере, правильные вызовы /etc/bashrc, все остальное было в порядке ... оказывается, это является причиной проблем с упаковкой.
Дхаупин
См. Также unix.stackexchange.com/a/61608/2221
astrojuanlu
1
Похоже, хорошее решение. Но это не работает в моей сессии SSH, хотя. Не уверен почему. Я выполнил команду shopt -s checkwinsizeв сеансе SSH. Но упаковка сохраняется.
Цян Сюй
Это была именно моя проблема - пользователь .bashrc не вызывал / etc / bashrc и поэтому создавал беспорядок.
Sobrique
9

Как упоминалось в других ответах, непечатаемые последовательности, такие как, \e[0;30mдолжны быть обернуты \[...\].

Кроме того (и то , что я не вижу , упоминается еще) это , кажется , что \r\nдолжно быть вне из \[...\]если у вас есть многострочный запрос на. Мне понадобилось несколько проб и ошибок, чтобы наконец понять это.

Geraden
источник
8

Однажды я где-то читал (не знаю где), что использую, \001а \002не могу \[и \]могу решить эту проблему. Это для меня.

Кстати, определение PS1 не должно выглядеть уродливо.

green="\001$(tput setaf 2)\002"
blue="\001$(tput setaf 4)\002"
dim="\001$(tput dim)\002"
reset="\001$(tput sgr0)\002"

PS1="$dim[\t] " # [hh:mm:ss]
PS1+="$green\u@\h" # user@host
PS1+="$blue\w\$$reset " # workingdir$

export PS1
unset green blue dim reset
phil294
источник
2
Мой PS1 вызывает команду, которая вызывает escape-последовательности printf, вызывая проблему OP. Только это решение решает проблему для меня.
РикМишам
7

Это звучит как проблема с настройками переменных COLUMNS& LINESenvironment. Когда вы изменяете размер окна, они обычно устанавливаются автоматически с помощью gnome-терминала (я полагаю), вы можете принудительно установить их вручную, введя команду resize.

пример

Если я изменю размер моего gnome-терминала на 79x17, мои переменные будут выглядеть так:

$ echo $COLUMNS; echo $LINES
79
17

Я могу заставить это так:

$ resize
COLUMNS=79;
LINES=17;
export COLUMNS LINES;
SLM
источник
1
Интересно, но не помогает.
Muricula
1
Это исправило мою проблему: неправильно выполнялась перенос строк после запуска команды «screen». Спасибо!!
nukeguy
5

Чтобы предотвратить перенос, вы также можете увеличить количество столбцов, используя, например,

stty columns 120
Ишмаэль
источник
1
не очень хорошая идея, она
ужасно
3

Также та же проблема может быть вызвана использованием широких символов Юникода (например, https://stackoverflow.com/a/34812608/1657819 ). Вот фрагмент кода, вызывающий проблему (обратите внимание на $Greenи $Redправильно экранированные строки цвета):

FancyX='\342\234\227'
Checkmark='\342\234\223'


# Add a bright white exit status for the last command
PS1="$White\$? "
# If it was successful, print a green check mark. Otherwise, print
# a red X.
if [[ $Last_Command == 0 ]]; then
    PS1+="$Green$Checkmark "
else
    PS1+="$Red$FancyX "
fi

Bash не может правильно рассчитать длину, поэтому самым простым способом может быть экранирование двух из трех частей этих широких символов.

FancyX='\[\342\234\]\227'
Checkmark='\[\342\234\]\223'
Крестный отец
источник
Имеет смысл. Я думаю, что bash считает символы. Поскольку X принимает один символ, но записывается как 3, нужно приложить 2 из них, чтобы исправить счет. Ответ @blauhirn также объясняет, как это сделать в функции с \001и \002.
Акостадинов
К вашему сведению, вот как вы выясните, как выводить многобайтовые символы
Юникода