Как получить длинные командные строки для переноса на следующую строку?

108

Что-то, что я заметил в Ubuntu в течение долгого времени, меня расстраивало, когда я набираю команду в командной строке, которая становится длиннее (шире) ширины терминала, вместо переноса на новую строку, она возвращается к столбец 1 в той же строке и начинает перезаписывать начало моей командной строки. (На самом деле она не перезаписывает действительную команду, но визуально она перезаписывает отображаемый текст).

Трудно объяснить, не видя этого, но, скажем, мой терминал был 20 символов в ширину (мой больше похож на 120 символов - но для примера), и я хочу повторить английский алфавит. Что я печатаю это:

echo abcdefghijklmnopqrstuvwxyz

Но как выглядит мой терминал перед нажатием клавиши:

pqrstuvwxyzghijklmno

Когда я нажимаю войти, это эхо

abcdefghijklmnopqrstuvwxyz

поэтому я знаю, что команда была получена правильно. Это просто обернуло мое печатание после «о» и началось с той же строки.

Что бы я ожидал, если бы я набрал эту команду на терминале шириной всего 20 символов, это было бы так:

echo abcdefghijklmno
pqrstuvwxyz

Справочная информация: я использую bash в качестве оболочки, и у меня есть эта строка в моем ~ / .bashrc:

set -o vi

чтобы иметь возможность перемещаться по командной строке с помощью команд VI. В настоящее время я использую сервер Ubuntu 10.10 и подключаюсь к серверу с помощью Putty.

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

Это также происходит, когда я возвращаюсь к предыдущим командам в истории (я нажимаю клавишу Esc, затем «K», чтобы вернуться к предыдущим командам) - когда я получаю предыдущую команду, длина которой была больше ширины терминала, командная строка получает покалеченный, и я не могу сказать, где я в команде.

Единственный обходной путь, который я нашел, чтобы увидеть всю длинную команду, - это нажать «Esc-V», которая открывает текущую команду в редакторе VI.

Я не думаю, что у меня есть что-то странное в моем файле .bashrc. Я закомментировал строку "set -o vi", и у меня все еще была проблема.

Я скачал свежую копию Putty и не внес никаких изменений в конфигурацию - я просто набрал имя хоста для подключения, и у меня все еще есть проблема, поэтому я не думаю, что это что-то с Putty (если мне не нужно внести некоторые изменения в конфигурацию)

У кого-нибудь еще была такая проблема, и может кто-нибудь подумать, как ее исправить?

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

Это был мой файл .bashrc. Я скопировал один и тот же профиль с машины на машину, и я использовал специальные символы в моем $ PS1, которые каким-то образом выбрасывают его. Теперь я придерживаюсь стандартных переменных bash для моего $ PS1.

Спасибо @ ændrük за подсказку .bashrc!

... Конец редактирования ...

BrianH
источник
1
Просто чтобы убедиться, что проблема не связана с вашим файлом .bashrc, я бы рекомендовал временно заменить его на копию /etc/skel/.bashrc. Имейте в виду, что вам нужно будет повторно подключиться, чтобы изменения вступили в силу, и обязательно сохраните резервную копию своего собственного .bashrc.
ændrük
1
Какое терминальное приложение вы используете? Поведение, которое вы описываете, не является обычным, конечно, не по умолчанию.
Жоау Пинту
В оболочках, в которых я работал (и в Cisco CLI), вы также можете нажать Ctrl-L, чтобы снова отобразить набираемую строку, даже если она находится за кадром. В вашей ситуации это может привести к неправильному выводу, о котором вы говорите, но мне было бы любопытно.
belacqua
3
Не стесняйтесь создавать «ответ», объясняющий решение, и пометить его как принятый. Это может показаться немного глупым, но наличие правильного ответа помогает поддерживать организованность сайта и может более эффективно направлять других, у которых в будущем возникнут аналогичные проблемы.
Ондрюк
Согласно этому ответу на serverfault , используйтеtput smam
Samveen

Ответы:

136

Убедитесь, что все непечатаемые байты в вашем PS1 содержатся внутри \[ \]. В противном случае, bash посчитает их по длине подсказки. Он использует длину приглашения, чтобы определить, когда переносить строку.

Например, здесь bash считает подсказку шириной 19 столбцов, тогда как подсказка, отображаемая терминалом, имеет ширину всего 10 колонок ( My promptнаписана голубым и >написана цветом по умолчанию):

PS1='\e[36mMy prompt\e[0m>'         # bash count: 19, actual: 10

в то время как здесь он только подсчитывает приглашение как 10 столбцов шириной, потому что игнорирует байты между специальным \[и \]escape-символами:

PS1='\[\e[36m\]My prompt\[\e[0m\]>' # bash count: 10, actual: 10

Однако, для хорошей практики, используйте tputдля генерации экранирования терминала, а не для их жесткого кодирования:

cyan=$(tput setaf 6) # \e[36m
reset=$(tput sgr0)   # \e[0m
PS1='\[$cyan\]My prompt\[$reset\]>'

См. Http://mywiki.wooledge.org/BashFAQ/053 , а также http://wiki.bash-hackers.org/scripting/terminalcodes для получения дополнительной информации tput.

geirha
источник
3
Это отличное объяснение проблемы, которую не дает принятый ответ
Джейми Кук
В последней строке кода PS1='...': почему одинарные кавычки не препятствуют $cyanи не $resetзаменяют?
Андрыбак
2
@andrybak, они предотвращают $cyanи $resetзаменяют, но PS1оцениваются каждый раз, когда приглашение печатается. Вы можете увидеть это, попробовав, PS1='$var> 'а затем присвоить varразличные значения и посмотреть, как меняется подсказка. Затем попытайтесь PS1="$var> " заметить, что приглашение остается статичным; $varрасширился во время задания, не каждый раз PS1оценивается.
гейра
1
Это потрясающе. Большое спасибо за размещение этого! Это делает выход из квадратных скобок намного проще и удобочитаемее.
Phyatt
Как я делаю эту работу PS1=${PS1}"\e]2;$@\a". Я пыталсяPS1=${PS1}"\[\e]2;\]$@\[\a\]"
Рамана Редди
59

Я полагаю, вы настроили свои PS1цвета, верно?

Просто убедитесь, что у вас \[внутри PS1цитаты, предшествующей вашему набору цветов

Например:

PS1='\[\e[0;32m\u@\w/:\[\e[m '
wjandrea
источник
Мой PS1 был export PS1='^[[96m'$(hostname)'<^[[92m${PWD}^[[96m>^[[97m '- я давно его использую - он совместим с KSH ...
BrianH
2
Ух ты. Я использую терминальные подсказки с тех пор и никогда раньше не сталкивался с этой проблемой. Никогда бы не понял это. Благодарю.
bchurchill
3
использование \ [при использовании простых кавычек приводит к непреднамеренной косой черте. также следует использовать] в конце магических символов, как отмечено в ответе с наибольшим количеством голосов
igorsantos07
2
-1 Не работает Вы должны обернуть непечатаемый раздел \[в начале и \]в конце.
wjandrea
@ igorsantos07 Двойная обратная косая черта \\[была опечаткой, вызванной редактированием. Я исправил это.
wjandrea
11

У меня была похожая проблема, и я наконец нашел простое решение.

Добавьте следующую строку в ваш .bashrcфайл:

COLUMNS=250

Затем введите, source ~/.bashrcчтобы получить желаемый эффект.

Deboshree
источник
В некоторых случаях, например, в узких разделителях терминатора, проблема не в цветах символов Promt, а в неправильном значении COLUMNS. Этот ответ вывел меня из очень надоедливой дыры!
Карлес Сала
1
Выход из системы не требуется. Есть source .bashrc. Ваша подсказка будет обновлена ​​немедленно
Сергей Колодяжный
1
Я обнаружил, что, поскольку у меня не было установленного setwinsizeнабора для моего bash, поэтому он не обновлял COLUMNS правильно, см. Unix.stackexchange.com/a/167911/8337
rogerdpack
1
Я export COLUMNS=250последовал за ним export TERM=xtermи был счастлив.
Филипп Кернс
5

У меня была та же проблема с настраиваемым цветным приглашением, хотя я содержал цветовые коды внутри \[и \]разделители. Оказывается, что у bash есть проблемы с отображением цветов внутри функции . Я просто использовал переменные для моего приглашения, и хотя мой .bashrc немного менее элегантен, теперь все работает хорошо.

reentim
источник
Если кто-то все еще читает это, на самом деле возможно избежать цветов в функции. Смотрите этот ответ по связанному вопросу.
wjandrea
3

Чтобы сделать PS1, нужно добавить следующую строку:

stty columns 1000

Например,

stty columns 1000
PS1='\[\e[0;32m\u@\w/:[\e[m '

однако это влияет на другие команды Unix, такие как ls и man.

Геннадий
источник
1
Это работает в OSX.
Расхадафи
4
Это также плохо влияет на vim. Пожалуйста, не используйте это.
полугодие
0

У меня была эта проблема при подключении в tmux. Проблема была в том, что у меня был ipythonсеанс в фоновом режиме ( ctrl + z), и это как-то нарушало перенос строк. Как только я прекратил ( fg, ctrl+d+d) мой терминал начал работать должным образом

Поэтому проверяйте, не остановились ли интерактивные подсказки.

Ciprian Tomoiagă
источник
0

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

Мой начальный PS1 был

PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$"

Проблема была в том, что я пытался изменить заголовок своего терминала, а также командную строку. То , как я сделал это, добавив \[\033]0;\]Title\aк PS1 переменной.

Так что теперь мой PS1 был:

PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$\[\033]0;\]Title\a"

Это испортило мне черту. Я наконец понял, что bash, похоже, не нравится \aв конце. Чтобы обойти это, я поместил заголовок в переменную, которая, казалось, исправила это.

TITLE="\033]0;Title\a"
PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$\[$TITLE\]"
Ciarán J. Hagen
источник
0

\[и \]не работал на меня. Я думаю, что-то отличалось в том, как я генерировал приглашение (из внешней программы), или потому что мое приглашение было «динамическим».

После прочтения этого я обнаружил , что вы можете избежать цветовых кодов с 0x01и 0x02байтов.

Например, я использую специальную версию Chalk и оборачиваю цвета, используя это:

const Chalk = require('@nasc/chalk');

const chalk = new Chalk.constructor({
  wrapper: {
    pre: '\1',
    post: '\2',
  }
});
mpen
источник