Como obtenho 'read' para ecoar todas as entradas, exceto a linha final no final da digitação?

3

Pressionar Enter ainda faz seu trabalho de delimitador, mas o comando read apenas termina silenciosamente, evitando mexer na rolagem do console. Basicamente, um read -s que afeta apenas a linha final.

    
por glarry 28.01.2018 / 10:56

2 respostas

0

Você poderia invocar o editor de linhas do zsh (que é totalmente configurável e geralmente muito mais avançado que readline (que o bash pode invocar com read -e )) como:

var=$(
  saved_tty=$(stty -g)
  var=default-value zsh -c '
    zle-line-finish() { # hook run upon leaving the line editor (zle)
      CURSOR=$#BUFFER # move the cursor to the end
      zle -R          # force a redraw of the editor
      printf %s $BUFFER # output value on stdout
      kill $$ # kill ourself to prevent zle cleanup
    }
    zle -N zle-line-finish
    vared -p "Text before [" var'
  # we need to restore the tty settings by ourselves, as we prevented zsh
  # from doing so when killing it:
  stty "$saved_tty"
)
printf '] Text after\n'

printf 'var = "%s"\n' "$var"

Ao correr, isso dá:

Text before [value edited] Text after
var = "value edited"

Enquanto bash agora permite ligar chaves a widgets de código de shell, ele limpa o conteúdo da linha atual antes de executar o widget, então você teria que redesenhar o prompt e o valor em seu Return handler:

var=$(prompt="Text before [" var=default-value bash -c '
  bind -x '\''"\r":printf >&2 %s "$prompt$READLINE_LINE";  printf %s "$READLINE_LINE"; exit'\'' 2> /dev/null
  IFS= read -rep "$prompt" -i default-value')

printf '] Text after\n'
printf 'var = "%s"\n' "$var"
    
por 29.01.2018 / 14:36
2

Sabendo que a leitura define a variável de leitura (com a opção n1 ) para um valor vazio, se o caractere de leitura for uma entrada, você poderá fazer algo como:

#!/bin/bash

while IFS= read -srn1 a ;do
    [[ "${a+x$a}" = "x" ]] && break
    var=$var$(printf '%s' "$a")
    printf '%s' "$a"
done
printf '\n%s\n' "$var"

Observe que os caracteres capturados pelo stty ou por outros não serão convertidos para um valor de byte:

Todos os caracteres de controle, exceto:

  1. ^ C (ASCII 03 ETX)
  2. ^ J (ASCII 0A LF)
  3. ^ M (ASCII 0D CR)
  4. ^ Z (ASCII 1A SUB)
  5. ^ \ (ASCII 1C FS)

Para realmente "ver" os caracteres backspace em relação aos anteriores, adicione esse loop para imprimir var (logo após o código acima):

echo
while IFS= read -srn1 a; do
    printf '%s' "$a"
    sleep 0.5
done <<<"$var"

Editar 3

Para fazer o backspace apagar um caractere, não capturar esse caractere e imprimir a string modificada, tente isto:

#!/bin/bash

while IFS= read -srn1 a ;do
    [[ "${a+x$a}" = "x" ]] && break

    if [[ $a = $'\x7f' || $a = $'\x08' ]]; then
        var=${var%?}
        [[ $a = $'\x7f' ]] && printf '\x0d%s \x08' "$var"
        [[ $a = $'\x08' ]] && printf '\x0d%s ' "$var"
    else
        var=$var$(printf '%s' "$a")
    fi

    printf '%s' "$a"
done
printf '\n%s\n' "$var"
printf '%s' "$var" | od -An -tx1

while IFS= read -srn1 a; do
    printf '%s' "$a"
    sleep 0.5
done <<<"$var"
    
por 28.01.2018 / 17:27

Tags