Jak uzyskać długie wiersze poleceń, aby zawinąć do następnego wiersza?


108

To, co zauważyłem w Ubuntu od dłuższego czasu, było dla mnie frustrujące, gdy piszę polecenie w wierszu polecenia, które staje się dłuższe (szersze) niż szerokość terminalu, zamiast owijania do nowej linii, wraca do kolumna 1 w tym samym wierszu i zaczyna nadpisywanie początku mojej linii poleceń. (W rzeczywistości nie zastępuje rzeczywistego polecenia, ale wizualnie zastępuje wyświetlany tekst).

Trudno to wyjaśnić, nie widząc go, ale powiedzmy, że mój terminal miał 20 znaków szerokości (mój ma więcej niż 120 znaków - ale dla przykładu) i chcę powtórzyć alfabet angielski. To, co wpisuję, to:

echo abcdefghijklmnopqrstuvwxyz

Ale zanim wcisnę klawisz, wygląda mój terminal:

pqrstuvwxyzghijklmno

Kiedy nacisnę klawisz Enter, odbija się echem

abcdefghijklmnopqrstuvwxyz

więc wiem, że polecenie zostało poprawnie odebrane. Po prostu owinął moje pisanie po „o” i zaczął od nowa w tej samej linii.

Oczekiwałbym, że tak się stanie, gdybym wpisał to polecenie na terminalu o szerokości zaledwie 20 znaków, to:

echo abcdefghijklmno
pqrstuvwxyz

Tło: używam bash jako mojej powłoki i mam ten wiersz w moim ~ / .bashrc:

set -o vi

aby móc poruszać się po linii poleceń za pomocą komend VI. Obecnie używam serwera Ubuntu 10.10 i łączę się z serwerem za pomocą Putty.

W każdym innym środowisku, w którym pracowałem, wpisanie długiego wiersza polecenia spowoduje dodanie nowego wiersza pod wierszem, nad którym pracuję, gdy moje polecenie wydłuży się poza szerokość terminala i gdy będę wpisywać, mogę zobaczyć moje polecenie na 2 różne linie. Ale tak długo, jak pamiętam używanie Ubuntu, moje długie polecenia zajmują tylko 1 linię.

Dzieje się tak również wtedy, gdy wracam do poprzednich poleceń w historii (wciskam Esc, a następnie „K”, aby wrócić do poprzednich poleceń) - kiedy przechodzę do poprzedniego polecenia, które było dłuższe niż szerokość terminala, wiersz poleceń otrzymuje zniekształcony i nie mogę powiedzieć, gdzie jestem w poleceniu.

Jedynym obejściem, które obejrzałem, aby zobaczyć całe długie polecenie, jest naciśnięcie „Esc-V”, co otwiera bieżące polecenie w edytorze VI.

Nie sądzę, że mam coś dziwnego w moim pliku .bashrc. Skomentowałem linię „set -o vi” i nadal miałem problem.

Pobrałem świeżą kopię Putty i nie wprowadziłem żadnych zmian w konfiguracji - po prostu wpisałem nazwę hosta, aby się połączyć, i nadal mam problem, więc nie sądzę, że to nic z Putty (chyba że muszę wprowadzić zmiany w konfiguracji)

Czy ktoś jeszcze miał ten problem i czy ktoś może wymyślić, jak go naprawić?

Edytować

To był mój plik .bashrc. Skopiowałem ten sam profil z maszyny na maszynę i użyłem znaków specjalnych w moim $ PS1, które w jakiś sposób go wyrzucają. Teraz trzymam się standardowych zmiennych bash dla mojego $ PS1.

Dzięki @ ændrük za wskazówkę dotyczącą .bashrc!

... Zakończ edycję ...


1
Aby mieć pewność, że problem nie jest spowodowany plikiem .bashrc, zalecamy tymczasowe zastąpienie go kopią pliku /etc/skel/.bashrc. Pamiętaj, że musisz ponownie połączyć, aby zmiany odniosły skutek, i pamiętaj o utworzeniu kopii zapasowej własnego pliku .bashrc.
ændrük

1
Z jakiej aplikacji terminalowej korzystasz? Opisywane zachowanie nie jest normalne, z pewnością nie jest domyślne.
João Pinto

W powłokach, w których pracowałem (i w Cisco CLI) możesz również wpisać Ctrl-L, aby ponownie wyświetlić wiersz, który wpisujesz, nawet jeśli jest poza ekranem. W twojej sytuacji może to nadal powodować uszkodzenie wyjścia, o którym mówisz, ale byłbym ciekawy.
belacqua

3
Utwórz odpowiedź wyjaśniającą rozwiązanie i oznacz ją jako zaakceptowaną. To może wydawać się trochę głupie, ale posiadanie właściwej odpowiedzi pomaga utrzymać porządek na stronie i może skuteczniej prowadzić innych, którzy mają podobne problemy w przyszłości.
ændrük

Zgodnie z odpowiedzią natput smam
błąd serwera

Odpowiedzi:


136

Upewnij się, że wszystkie bajty niedrukowalne na twoim PS1 są zawarte \[ \]. W przeciwnym razie bash policzy je w długości monitu. Używa długości monitu, aby określić, kiedy należy zawinąć linię.

Na przykład tutaj bash liczy monit o szerokości 19 kolumn, podczas gdy monit wyświetlany przez terminal ma tylko 10 kolumn ( My promptnapisany na niebiesko i >zapisany w domyślnym kolorze):

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

podczas gdy tutaj liczy tylko wiersz jako szerokość 10 kolumn, ponieważ ignoruje bajty między znakiem specjalnym \[i \]znakami ucieczki:

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

Jednak dla dobrej praktyki używaj tputdo generowania znaków ucieczki terminala zamiast kodowania ich na stałe:

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

Zobacz http://mywiki.wooledge.org/BashFAQ/053 , a także http://wiki.bash-hackers.org/scripting/terminalcodes, aby uzyskać więcej informacji tput.


3
To świetne wyjaśnienie problemu, którego nie zapewnia zaakceptowana odpowiedź
Jamie Cook

W ostatnim wierszu kodu PS1='...': dlaczego nie pojedyncze cytaty zapobiegania $cyani $resetod podstawienia?
andrybak

2
@andrybak, zapobiegają $cyani $resetsą zastępowane, ale PS1są oceniane za każdym razem, gdy monit jest drukowany. Możesz to zobaczyć, próbując PS1='$var> 'następnie podać varróżne wartości i zobaczyć, jak monit zmienia się. Następnie spróbuj PS1="$var> " zauważyć, że monit pozostaje statyczny; $varzostał rozszerzony podczas zadania, nie za każdym razem PS1jest oceniany.
geirha

1
To jest niesamowite. Dziękuję bardzo za opublikowanie tego! Dzięki temu ucieczka od nawiasów kwadratowych jest znacznie łatwiejsza i bardziej czytelna.
phyatt,

Jak sprawiam, że to działa PS1=${PS1}"\e]2;$@\a". PróbowałemPS1=${PS1}"\[\e]2;\]$@\[\a\]"
Ramana Reddy,

59

Myślę, że masz skonfigurowane PS1kolory, prawda?

Po prostu upewnij się, że masz \[wewnątrz PS1cytatu poprzedzającego zestaw kolorów

Na przykład:

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

Mój PS1 był export PS1='^[[96m'$(hostname)'<^[[92m${PWD}^[[96m>^[[97m '- używam go od dłuższego czasu - jest kompatybilny z KSH ...
BrianH

2
Łał. Od zawsze używam podpowiedzi terminalowych i nigdy wcześniej nie miałem tego problemu. Nigdy by tego nie rozgryzł. Dzięki.
bchurchill 30.09.13

3
użycie \ [podczas korzystania z prostych cudzysłowów daje niezamierzone ukośnik. należy też użyć] na końcu magicznych znaków, jak zaznaczono w najlepiej głosowanej odpowiedzi
igorsantos07

2
-1 nie działa. Na początku i na końcu należy owinąć sekcję niedrukowalną . \[\]
wjandrea

@ igorsantos07 Podwójny odwrotny ukośnik \\[był literówką spowodowaną edycją. Naprawiłem to.
wjandrea

11

Miałem podobny problem i wreszcie znalazłem proste rozwiązanie.

Dodaj następujący wiersz do .bashrcpliku:

COLUMNS=250

Następnie wpisz, source ~/.bashrcaby uzyskać pożądany efekt.


W niektórych przypadkach, na przykład w wąskich podziałach terminatora, problemem nie są znaki koloru promt, lecz niewłaściwa wartość COLUMNS. Ta odpowiedź wyciągnęła mnie z bardzo niepokojącej dziury!
Carles Sala

1
Wylogowanie nie jest konieczne. Zrobić source .bashrc. Twoje
zapytanie

1
Stwierdziłem, że skoro nie setwinsizeustawiłem shopt na moją bash, więc nie aktualizowałem poprawnie KOLUMN
rogerdpack

1
I nie export COLUMNS=250następuje export TERM=xtermi był zadowolony.
Philip Kearns

5

Miałem ten sam problem z niestandardowym kolorowym monitem, mimo że zawierałem kody kolorów wewnątrz \[i \]ograniczniki. Okazuje się, że bash ma problemy z odbiciem kolorów z wnętrza funkcji . Skończyło się na tym, że użyłem zmiennych do pytania i chociaż mój .bashrc jest trochę mniej elegancki, wszystko działa teraz dobrze.


Jeśli ktoś nadal to czyta, możliwe jest uniknięcie kolorów w funkcji. Zobacz tę odpowiedź na powiązane pytanie.
wjandrea

3

Prostą rzeczą byłoby dodanie następującego wiersza przed ustawieniem PS1:

stty columns 1000

Na przykład,

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

wpływa to jednak na inne polecenia unixowe, takie jak ls i man.


1
To działa w OSX.
raskhadafi

4
Wpływa to również źle na vima. Proszę nie używać tego.
justhalf

0

Miałem ten problem po podłączeniu do Tmux. Problem polegał na tym, że miałem ipythonsesję w tle ( ctrl + z) i że jakoś zepsuło się zawijanie linii. Gdy tylko go zakończyłem ( fg, ctrl+d+d) mój terminal zaczął działać poprawnie

Sprawdź więc wszelkie zatrzymane interaktywne monity.


0

Właśnie miałem ten sam problem z lekkim zwrotem i pomyślałem, że podzielę się również moim rozwiązaniem, aby dodać mój mały niuans: D

Mój początkowy PS1 to był

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

Problemem było to, że próbowałem zmienić tytuł terminalu, a także wiersz polecenia. Sposób, w jaki to zrobiłem, polegał na dodaniu \[\033]0;\]Title\ado zmiennej PS1 .

Więc teraz mój PS1 to:

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

To pomieszało mi owijanie linii. W końcu doszedłem do wniosku, że bash nie wydaje się mieć \akońca. Aby to obejść, umieściłem tytuł w zmiennej, która wydawała się go naprawić.

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

0

\[i \]nie działało dla mnie. Wydaje mi się, że było coś innego w tym, jak generowałem monit (z zewnętrznego programu) lub dlatego, że mój monit był „dynamiczny”.

Po przeczytaniu tego stwierdziłem, że można właściwie uniknąć kodów kolorów za pomocą bajtów 0x01i 0x02.

np. używam specjalnej wersji kredy i owijam kolory za pomocą tego:

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

const chalk = new Chalk.constructor({
  wrapper: {
    pre: '\1',
    post: '\2',
  }
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.