Jak sprawić, aby bash wstawił monit w nowym wierszu po poleceniu kota?


17

Co dostaję:

host:~ user$ cat example.txt
some texthost:~ stas$

Co chcę uzyskać:

host:~ user$ cat example.txt
some text
host:~ stas$

Czy mogę w ten sposób catzachowywać się w ten sposób?

Używam bash na Mac OS X.

Odpowiedzi:


15

Większość narzędzi uniksowych jest zaprojektowana do pracy z plikami tekstowymi. Plik tekstowy składa się z sekwencji wierszy. Linia składa się z sekwencji drukowalnych znaków kończących się znakiem nowej linii. W szczególności ostatnim znakiem niepustego pliku tekstowego jest zawsze znak nowej linii. Oczywiście example.txtzawiera tylko some textbez ostatniej nowej linii, więc nie jest to plik tekstowy.

catwykonuje prostą pracę; przekształcanie dowolnych plików w pliki tekstowe nie jest częścią tego zadania. Niektóre inne narzędzia zawsze przekształcają dane wejściowe w pliki tekstowe; jeśli nie masz pewności, czy wyświetlany plik kończy się nową linią, spróbuj uruchomić awk 1zamiast cat.

Możesz sprawić, by bash wyświetlił monit w następnym wierszu, jeśli poprzednie polecenie opuściło kursor w miejscu innym niż ostatni margines. Umieść to w swoim .bashrc(wariant GetFree propozycji Dennisa Williamsona ):

shopt -s promptvars
PS1='$(printf "%$((COLUMNS-1))s\r")'$PS1

Dziękuję bardzo za działające rozwiązanie i zwięzłe wyjaśnienie! Rozumiem, że to trochę dla biednych cat, więc zachowam to jako ostateczność na czas, gdy ten problem zacznie mnie ponownie niepokoić.
Stanislav Shabalin

Ponieważ jest to preferencja bash, czy może złamać polecenia potokowe?
Stanislav Shabalin

1
@StanislavShabalin To nie wpływa na orurowanie, tylko na monit.
Gilles „SO- przestań być zły”

Muszę usunąć „-1” po „KOLUMNACH”, aby to działało poprawnie.
rafak

To rozwiązanie powoduje przesuwanie monitu podczas zmiany rozmiaru okna terminala. Odkryłem, że aby to działało niezawodnie, musiałem pobrać bieżącą kolumnę PROMPT_COMMANDi, jeśli nie jest to 0, użyj \nznaku nowej linii ( ) jako pierwszego znaku PS1.
Brian Donovan,

10

Wolę następującą metodę ...

cat example.txt ; echo

To nie ocenia zawartości example.txtani nie dodaje nowego wiersza. To tylko echo nowego wiersza po skończeniu kota, jest łatwe do zapamiętania i nikt nie zastanawia się, czy poprawnie używa silnych, czy słabych cytatów.

Jedynym minusem jest to, że dostaniesz dodatkową linię nowej linii, jeśli plik ma własną linię końcową.


7

Zacząłem używać odpowiedzi @ Gilles, ale stwierdziłem, że jeśli terminal zmieni liczbę kolumn, monit nie będzie już na początku wiersza, jak oczekiwano. Może się to zdarzyć z różnych powodów, w tym podziałów tmux / screen, ręcznego zmieniania rozmiaru kontenera GUI, zmian czcionek itp.

To, czego naprawdę chciałem, to coś, co dodałoby nowy wiersz, gdyby terminal zaczął drukować swój monit w innym miejscu niż pierwsza kolumna. Aby to zrobić, musiałem dowiedzieć się, jak uzyskać bieżącą kolumnę, której użyłem tej odpowiedzi . Ostateczna konfiguracja monitów roboczych jest poniżej:

###
# Configure PS1 by using the old value but ensuring it starts on a new line.
###
__configure_prompt() {
  PS1=""

  if [ "$(__get_terminal_column)" != 0 ]; then
    PS1="\n"
  fi

  PS1+="$PS1_WITHOUT_PREPENDED_NEWLINE"
}

###
# Get the current terminal column value.
#
# From /programming//a/2575525/549363.
###
__get_terminal_column() {
  exec < /dev/tty
  local oldstty=$(stty -g)
  stty raw -echo min 0
  echo -en "\033[6n" > /dev/tty
  local pos
  IFS=';' read -r -d R -a pos
  stty $oldstty
  echo "$((${pos[1]} - 1))"
}

# Save the current PS1 for later.
PS1_WITHOUT_PREPENDED_NEWLINE="$PS1"

# Use our prompt configuration function, preserving whatever existing
# PROMPT_COMMAND might be configured.
PROMPT_COMMAND="__configure_prompt;$PROMPT_COMMAND"

Korzystam z tego rozwiązania, ale kiedy próbuję wkleić do powłoki polecenia zawierające wiele wierszy, wydaje się, że kończą część / wszystkie linie po wklejeniu pierwszego. Czy jest na to jakieś rozwiązanie?
tylko

@onlynone być może twoje polecenia nie są wykonywane indywidualnie i na czas __get_terminal_column?
Androbin,

Zamiast tego po PS1="\n"prostu mam echoi nie muszę modyfikować PS1.
Androbin,

4

Problemem może być to, że plik example.txt nie ma nowego wiersza na końcu pliku.


2
Chodzi o to, że nie obchodzi mnie, czy plik ma na końcu nowy wiersz, czy nie. Chcę być w stanie zobaczyć, jak wyjście kota jest bardziej wyraźne, a nie tak destrukcyjne :-) I rozumiem, że to nie catjest praca, więc prawdopodobnie szukam jakiegoś obejścia.
Stanislav Shabalin

1
To taka brak odpowiedzi, example.txtbrak nowej linii na końcu pliku jest sednem pytania.
Willem D'Haeseleer,

2

Jeśli nalegasz na użycie cat, działa to w przypadku obu typów plików, z lub bez znaku nowej linii na końcu:

echo "`cat example.txt`"

Możesz zmienić go w funkcję o dowolnej nazwie (nawet cat) w .bashrc:

cat1(){ echo "`/bin/cat $@`";}

1
Teraz to trochę za dużo, nawet jeśli to działa ;-) Dzięki jednak!
Stanislav Shabalin

0

możesz również dodać do .bashrc

PROMPT_COMMAND="printf '\n';$PROMPT_COMMAND"

pracuje dla mnie.


1
Dodałoby to również dodatkową pustą linię w terminalu, ilekroć narzędzie wysyła coś, co jest poprawnie zakończone przez nową linię.
Kusalananda

To prawda. Ale to proste, a jeśli nie przeszkadza ci to mieć dodatkową linię ...
klaus
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.