¿Cómo consigo largas líneas de comando para ajustar a la siguiente línea?

108

Algo que noté en Ubuntu durante mucho tiempo y que me ha frustrado es cuando escribo un comando en la línea de comando que se hace más largo (más ancho) que el ancho del terminal, en lugar de ajustarse a una nueva línea, vuelve a columna 1 en la misma línea y comienza a sobrescribir el comienzo de mi línea de comando. (En realidad, no sobrescribe el comando real, pero visualmente, sobrescribe el texto que se mostró).

Es difícil de explicar sin verlo, pero digamos que mi terminal tenía 20 caracteres de ancho (el mío tiene más de 120 caracteres, pero solo por un ejemplo), y quiero hacer eco del alfabeto inglés. Lo que escribo es esto:

echo abcdefghijklmnopqrstuvwxyz

Pero cómo se ve mi terminal antes de presionar la tecla es:

pqrstuvwxyzghijklmno

Cuando presiono enter, se hace eco

abcdefghijklmnopqrstuvwxyz

entonces sé que el comando se recibió correctamente. Simplemente envolvió mi escritura después de la "o" y comenzó de nuevo en la misma línea.

Lo que esperaría que sucediera, si escribiera este comando en una terminal que solo tenía 20 caracteres de ancho, sería esto:

echo abcdefghijklmno
pqrstuvwxyz

Antecedentes: estoy usando bash como mi shell, y tengo esta línea en mi ~ / .bashrc:

set -o vi

para poder navegar por la línea de comandos con comandos VI. Actualmente estoy usando el servidor Ubuntu 10.10 y me estoy conectando al servidor con Putty.

En cualquier otro entorno en el que haya trabajado, si escribo una línea de comando larga, agregará una nueva línea debajo de la línea en la que estoy trabajando cuando mi comando sea más largo que el ancho del terminal y cuando sigo escribiendo puedo ver mi comando en 2 líneas diferentes Pero mientras pueda recordar haber usado Ubuntu, mis comandos largos solo ocupan 1 línea.

Esto también sucede cuando vuelvo a los comandos anteriores en el historial (presiono Esc, luego 'K' para volver a los comandos anteriores): cuando llego a un comando anterior que era más largo que el ancho del terminal, la línea de comando se pone destrozado y no puedo decir dónde estoy en el comando.

La única solución que he encontrado para ver todo el comando largo es presionar "Esc-V", que abre el comando actual en un editor de VI.

No creo que tenga nada extraño en mi archivo .bashrc. Comenté la línea "set -o vi", y todavía tenía el problema.

Descargué una copia nueva de Putty y no realicé ningún cambio en la configuración; simplemente escribí mi nombre de host para conectarme y todavía tengo el problema, así que no creo que sea algo con Putty (a menos que necesite hacer algunos cambios de configuración)

¿Alguien más ha tenido este problema y alguien puede pensar en cómo solucionarlo?

Editar

Era mi archivo .bashrc. Copié el mismo perfil de máquina a máquina, y usé caracteres especiales en mi $ PS1 que de alguna manera lo están descartando. Ahora me quedo con las variables bash estándar para mi $ PS1.

¡Gracias a @ ændrük por el consejo sobre el .bashrc!

... Fin Editar ...

BrianH
fuente
1
Solo para estar seguro de que el problema no es causado por su archivo .bashrc, recomendaría reemplazarlo temporalmente con una copia de /etc/skel/.bashrc. Tenga en cuenta que deberá volver a conectarse para que los cambios surtan efecto y asegúrese de mantener una copia de seguridad de su propio .bashrc.
ændrük 01 de
1
¿Qué aplicación de terminal estás usando? El comportamiento que está describiendo no es habitual, ciertamente no es un defecto.
João Pinto
En los shells en los que he trabajado (y en Cisco CLI) también puede escribir Ctrl-L para volver a mostrar la línea que está escribiendo, incluso si está fuera de la pantalla. En su situación, eso aún puede producir el resultado roto del que está hablando, pero sería curioso.
belacqua
3
Siéntase libre de crear una "respuesta" que explique la solución y márquela como aceptada. Puede parecer un poco tonto, pero tener una respuesta adecuada ayuda a mantener el sitio organizado y puede guiar de manera más efectiva a otros que tengan problemas similares en el futuro.
ændrük
Según esta respuesta en serverfault , usetput smam
Samveen

Respuestas:

136

Asegúrese de que todos los bytes no imprimibles en su PS1 estén contenidos dentro \[ \]. De lo contrario, bash los contará en la longitud de la solicitud. Utiliza la longitud de la solicitud para determinar cuándo ajustar la línea.

Por ejemplo, aquí bash cuenta el aviso como 19 columnas de ancho, mientras que el aviso que muestra el terminal tiene solo 10 columnas de ancho ( My promptescrito en cian y >escrito en color predeterminado):

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

mientras que aquí solo cuenta el indicador como 10 columnas de ancho porque ignora los bytes entre el especial \[y los \]escapes:

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

Sin embargo, para una buena práctica, úselo tputpara generar los escapes de terminal en lugar de codificarlos:

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

Consulte http://mywiki.wooledge.org/BashFAQ/053 , y también http://wiki.bash-hackers.org/scripting/terminalcodes para obtener más información tput.

geirha
fuente
3
Esa es una gran explicación del problema que la respuesta aceptada no proporciona
Jamie Cook,
En la última línea de código PS1='...': ¿por qué las comillas simples no previenen $cyany $resetsustituyen?
andrybak
2
@andrybak, evitan $cyany $resetse sustituyen, pero PS1se evalúa cada vez que se imprime la solicitud. Puede ver esto intentando PS1='$var> 'y luego dar varvarios valores y ver cómo cambia la solicitud. Luego intente PS1="$var> " y observe que el mensaje permanece estático; $varse expandió durante la asignación, no todas las veces PS1se evalúa.
geirha
1
Esto es increíble. Muchas gracias por publicar esto! Hace que escapar de los corchetes sea mucho más fácil y más legible.
phyatt
Cómo hago que esto funcione PS1=${PS1}"\e]2;$@\a". Lo intentéPS1=${PS1}"\[\e]2;\]$@\[\a\]"
Ramana Reddy
59

Supongo que has configurado tu PS1con colores, ¿verdad?

Solo asegúrese de tener \[dentro de su PS1presupuesto antes de su conjunto de colores

Por ejemplo:

PS1='\[\e[0;32m\u@\w/:\[\e[m '
wjandrea
fuente
Mi PS1 fue export PS1='^[[96m'$(hostname)'<^[[92m${PWD}^[[96m>^[[97m ': he estado usando esa durante mucho tiempo, es compatible con KSH ...
BrianH
2
Guau. He estado usando mensajes de terminal desde siempre y nunca antes tuve este problema. Nunca lo habría descubierto. Gracias.
bchurchill
3
El uso de \ [al usar comillas simples produce una barra diagonal no deseada. también, debería usarse] al final de los caracteres mágicos, como se señala en la respuesta mejor votada
igorsantos07
2
-1 no funciona. Debe ajustar la sección sin impresión \[al principio y \]al final.
wjandrea
@ igorsantos07 La doble barra invertida \\[fue un error tipográfico causado por una edición. Lo he arreglado
wjandrea
11

Tuve un problema similar y finalmente encontré una solución simple.

Agregue la siguiente línea en su .bashrcarchivo:

COLUMNS=250

Luego escriba source ~/.bashrcpara obtener el efecto deseado.

Deboshree
fuente
En algunos casos, como las subdivisiones de terminador estrecho, el problema no está en los caracteres de color del indicador sino en un valor incorrecto de COLUMNAS. ¡Esta respuesta me sacó de un agujero muy molesto!
Carles Sala
1
Cerrar sesión es innecesario. Hacer source .bashrc. Su mensaje se actualizará inmediatamente
Sergiy Kolodyazhnyy
1
Descubrí que, dado que no tenía una tienda setwinsizeconfigurada para mi bash, por lo que no estaba actualizando COLUMNAS correctamente, vea unix.stackexchange.com/a/167911/8337
rogerdpack
1
Lo export COLUMNS=250seguí export TERM=xtermy fue feliz.
Philip Kearns el
5

Tuve el mismo problema con un indicador de color personalizado, a pesar de que contenía códigos de color \[y \]delimitadores. Resulta que bash tiene problemas para hacer eco de los colores dentro de una función . Terminé usando solo variables para mi solicitud, y aunque mi .bashrc es un poco menos elegante, todo funciona bien ahora.

reentim
fuente
Si alguien sigue leyendo esto, en realidad es posible escapar de los colores en una función. Vea esta respuesta en la pregunta vinculada.
wjandrea
3

Una cosa simple sería agregar la siguiente línea antes de configurar la PS1:

stty columns 1000

Por ejemplo,

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

sin embargo, esto afecta a otros comandos de Unix como ls y man.

Gennady
fuente
1
Eso funciona en OSX.
raskhadafi
44
Esto también afecta vim mal. Por favor no uses esto.
justhalf
0

Tuve este problema cuando me conecté en tmux. El problema fue que tuve una ipythonsesión en segundo plano ( ctrl + z) y que de alguna manera rompió el ajuste de línea. Tan pronto como lo terminé ( fg, ctrl+d+d) mi terminal comenzó a funcionar correctamente

Por lo tanto, compruebe si hay mensajes interactivos detenidos.

Ciprian Tomoiagă
fuente
0

Así que tuve el mismo problema con un ligero giro y pensé en compartir mi solución también, solo para agregar mi pequeño matiz: D

Mi PS1 inicial fue

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

El problema que tuve fue que estaba tratando de cambiar el título de mi terminal , así como el símbolo del sistema. La forma en que hice esto fue agregando \[\033]0;\]Title\aa la variable PS1 .

Entonces ahora mi PS1 era:

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

Esto estropeó la línea que me envolvía. Finalmente descubrí que a bash no parece gustarle tenerlo \aal final. Para evitar esto, puse el título en una variable, que parecía arreglarlo.

TITLE="\033]0;Title\a"
PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$\[$TITLE\]"
Ciarán J. Hagen
fuente
0

\[y \]no funcionó para mí Supongo que hubo algo diferente sobre cómo estaba generando el aviso (desde un programa externo), o porque mi aviso era "dinámico".

Después de leer esto , descubrí que realmente puedes escapar de los códigos de color con los bytes 0x01y 0x02.

Por ejemplo, estoy usando una versión especial de Chalk y envuelvo los colores usando esto:

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

const chalk = new Chalk.constructor({
  wrapper: {
    pre: '\1',
    post: '\2',
  }
});
mpen
fuente