Como fazer o bash colocar prompt em uma nova linha após o comando cat?

17

O que eu ganho:

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

O que eu quero obter:

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

Existe uma maneira que eu possa fazer me catcomportar assim?

Estou usando o bash no Mac OS X.

Stanislav Shabalin
fonte

Respostas:

15

A maioria das ferramentas unix é projetada para funcionar bem com arquivos de texto. Um arquivo de texto consiste em uma sequência de linhas. Uma linha consiste em uma sequência de caracteres imprimíveis que termina com um caractere de nova linha. Em particular, o último caractere de um arquivo de texto não vazio é sempre um caractere de nova linha. Evidentemente, example.txtcontém apenas some textsem nova linha final, portanto, não é um arquivo de texto.

catfaz um trabalho simples; transformar arquivos arbitrários em arquivos de texto não faz parte desse trabalho. Algumas outras ferramentas sempre transformam sua entrada em arquivos de texto; se você não tiver certeza de que o arquivo que você está exibindo termina com uma nova linha, tente executar em awk 1vez de cat.

Você pode fazer com que o bash exiba seu prompt na próxima linha se o comando anterior deixar o cursor em algum lugar que não seja a última margem. Coloque isso em sua .bashrc(variação do GetFree de uma proposta de Dennis Williamson ):

shopt -s promptvars
PS1='$(printf "%$((COLUMNS-1))s\r")'$PS1
Gilles 'SO- parar de ser mau'
fonte
Muito obrigado por uma solução funcional e explicação sucinta! Entendo que isso é um pouco demais para os pobres cat, por isso vou mantê-lo como último recurso no momento em que esse problema começar a me incomodar novamente.
Stanislav Shabalin
Como essa é a preferência do bash, ele pode quebrar os comandos de tubulação?
Stanislav Shabalin
1
@StanislavShabalin Isso não afeta a tubulação, apenas o prompt.
Gilles 'SO- stop be evil'
Preciso remover o "-1" depois de "COLUMNS" para que isso funcione corretamente.
Rafak
Esta solução faz com que o prompt se mova quando a janela do terminal é redimensionada. Descobri que, para fazer esse trabalho de maneira confiável, eu precisava inserir a coluna atual PROMPT_COMMANDe, se não for 0, usar uma nova linha ( \n) como o primeiro caractere PS1.
Brian Donovan
10

Eu prefiro o seguinte método ...

cat example.txt ; echo

Isso não avalia o conteúdo example.txtou, ocasionalmente, adiciona uma nova linha. É apenas ecoar uma nova linha quando o gato está pronto, é fácil de lembrar, e ninguém está pensando se eles estão usando citações fortes ou fracas corretamente.

A única desvantagem, na verdade, é que você obterá uma nova linha extra se o arquivo tiver sua própria linha final.

Amos
fonte
7

Comecei a usar a resposta de @ Gilles, mas descobri que, se o terminal alterasse o número de colunas, o prompt não estaria mais no início de uma linha, como esperado. Isso pode acontecer por vários motivos, incluindo tmux / screen splits, redimensionamento manual de um contêiner da GUI, alterações de fonte etc.

O que eu realmente queria era algo que adicionasse uma nova linha se o terminal começasse a imprimir seu prompt em algo diferente da primeira coluna. Para fazer isso, eu precisava descobrir como obter a coluna atual, que usei esta resposta para obter. A configuração final do prompt de trabalho está abaixo:

###
# 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
fonte
Eu uso essa solução, mas quando tento colar comandos de várias linhas no meu shell, parece que acabamos comendo parte / todas as linhas após a primeira colada. Há alguma solução para isso?
onlynone 8/08/18
@onlynone possivelmente seus comandos não são liberados individualmente e a tempo __get_terminal_column?
Androbin 10/11
Em vez de PS1="\n"apenas ter echoe não precisar modificar PS1.
Androbin 10/11
4

O problema pode ser que o seu exemplo.txt não tenha uma nova linha no final do seu arquivo.

Bonsi Scott
fonte
2
O problema é que não me importo se o arquivo tem uma nova linha no final ou não. Eu quero ver a saída do gato mais clara e não tão perturbadora :-) E eu entendo que não caté o trabalho dele, então provavelmente estou procurando alguma solução alternativa.
Stanislav Shabalin
1
Essa é uma não resposta, example.txtnão ter uma nova linha no final do arquivo, é o ponto principal da questão.
Willem D'Haeseleer 2/11
2

Se você insistir em usar cat, isso funcionará para os dois tipos de arquivos, com e sem uma nova linha no final:

echo "`cat example.txt`"

Você pode transformá-lo em uma função com um nome de sua escolha (par cat) em .bashrc:

cat1(){ echo "`/bin/cat $@`";}
woodengod
fonte
1
Agora isso é um pouco demais, mesmo que funcione ;-) Obrigado!
Stanislav Shabalin
0

você também pode adicionar ao .bashrc

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

funciona para mim.

klaus
fonte
1
Isso também adicionaria uma linha em branco extra no terminal sempre que um utilitário emitir algo que seja finalizado corretamente por uma nova linha.
Kusalananda
Isso é verdade. Mas é simples, e se isso não incomoda você ter uma linha extra ...
klaus