Maneira elegante de impedir que a substituição de comandos remova a nova linha à direita

6

Estou personalizando meu zsh PROMPT e chamando uma função que pode ou não echo uma string com base no estado de uma variável de ambiente:

function my_info {
    [[ -n "$ENV_VAR"]] && echo "Some useful information\n"
}

local my_info='$(my_info)'

PROMPT="${my_info}My awesome prompt $>"

Gostaria que a informação terminasse em uma nova linha à direita, de modo que, se estiver definida, ela apareça em sua própria linha:

Some useful information
My awesome prompt $>

No entanto, se não estiver definido, quero que o prompt esteja em uma única linha, evitando uma linha vazia causada por uma nova linha incondicional no meu prompt:

PROMPT="${my_info}  # <= Don't want that :)
My awesome prompt $>"

Atualmente, trabalho em torno do $(command substitution) removendo minha nova linha, sufixando-a com um caractere não imprimível, portanto, a nova linha não está perdendo mais:

[[ -n "$ENV_VAR"]] && echo "Some useful information\n\r"

Isto é obviamente um hack. Existe uma maneira limpa de retornar uma string que termina em uma nova linha?

Editar: Eu entendo o que causa a perda da nova linha à direita e por que isso acontece , mas nesta pergunta eu gostaria especificamente de saber como evitar esse comportamento (e eu não acho que esta solução alternativa se aplica no meu caso, já que estou procurando por uma nova linha "condicional".

Editar: Eu estou corrigido: o solução alternativa referenciada pode realmente ser uma solução bastante agradável (já que o prefixo de strings em comparações é um padrão comum e um pouco similar), exceto que não consigo funcionar adequadamente:

echo "Some useful information\n"x
  [...]
PROMPT="${my_info%x}My awesome prompt $>"

não tira o x para mim.

Edit: Ajustando a solução proposta para a estranheza que é a expansão imediata, isso funcionou para mim:

function my_info {
    [[ -n "$ENV_VAR"]] && echo "Some useful information\n"x
}

local my_info='${$(my_info)%x}'

PROMPT="$my_info My awesome prompt $>"

Você será o juiz se esta for uma solução melhor que a original. É um pouco mais explícito, eu acho, mas também parece um pouco menos legível.

    
por dtk 30.05.2015 / 03:49

2 respostas

3

Novas linhas finais são removidas das substituições de comandos. Mesmo o zsh não oferece uma opção para evitar isso. Então, se você quiser preservar as novas linhas finais, você precisa providenciar para que elas não sejam novas linhas finais.

A maneira mais fácil de fazer isso é imprimir um caractere extra (diferente de uma nova linha) após os dados que você deseja obter exatamente e remover esse caractere extra final do resultado da substituição do comando. Opcionalmente, você pode colocar uma nova linha depois desse caractere extra, que será removido de qualquer maneira.

No zsh, você pode combinar a substituição de comandos com a manipulação de strings para remover o caractere extra.

my_info='${$(my_info; echo .)%.}'
PROMPT="${my_info}My awesome prompt $>"

Em seu cenário, tome cuidado para que my_info não seja a saída do comando, é um fragmento de shell para obter a saída, que será avaliada quando o prompt for expandido. PROMPT=${my_info%x}… não funcionou porque tenta remover um x final do valor da variável my_info , mas termina com ) .

Em outros shells, isso precisa ser feito em duas etapas:

output=$(my_info; echo .)
output=${output%.}

No bash, você não seria capaz de chamar my_info diretamente de PS1 ; em vez disso, você precisaria chamá-lo de PROMPT_COMMAND .

PROMPT_COMMAND='my_info=$(my_info; echo .)'
PS1='${my_info%.}…'
    
por 31.05.2015 / 02:36
-1

Você pode fazer com que sua função produza os códigos de escape com escape, para que, quando expandida, ela se transforme na nova linha.

$ function my_info {
>    [[ -n "$ENV_VAR"]] && echo 'Some useful information\n'
>}
$ echo $(my_info)
Some useful information

$
    
por 30.05.2015 / 04:07