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.

Stanisław Shabalin
źródło

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
Gilles „SO- przestań być zły”
źródło
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ą.

Amos
źródło
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"
Brian Donovan
źródło
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.

Bonsi Scott
źródło
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 $@`";}
woodengod
źródło
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.

klaus
źródło
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