Formatando a saída: Sublinhado

4

Eu escrevi a seguinte função em ksh que imprime seu primeiro argumento na tela e sublinha com a quantidade apropriada de - character:

print_underlined () {
    word=$1 
    echo $word

    i=${#word}
    while [[ i -gt 0 ]]; do
        printf "-"
        (( i = $i - 1 ))
    done
    printf "\n"
}

exemplo:

$ print_underlined foobar
foobar
------
$

Gostaria de saber se existe uma maneira mais simples e elegante de exibir uma palavra sublinhada na tela.

Para o registro que estou usando:

  • Solaris 10
  • ksh88
por rahmu 14.05.2012 / 14:57

5 respostas

3

O núcleo da sua pergunta é a construção de uma string consistindo inteiramente de underscores com o mesmo tamanho de uma string existente. Em versões recentes do bash, ksh ou zsh, você pode construir essa string com a ${VARIABLE//PATTERN/REPLACEMENT} construct: underlines=${word//?/_} . Mas essa construção não existe no ksh88.

Em qualquer shell, você pode usar tr . Implementações compatíveis com POSIX de tr permitem escrever isto:

underlines=$(printf %s "$word" | tr -c '_' '[_*]')

Acho que o Solaris 10 tem um tr compatível com POSIX por padrão, mas pode haver uma implementação histórica (compatível com versões anteriores do Solaris). As implementações históricas de tr podem não entender a sintaxe [x*] , mas tendem a aceitar a seguinte sintaxe (que não é garantida pelo POSIX), para significar “substituir tudo o que não é uma nova linha por _ ":

underlines=$(echo "$word" | tr -c '0' '_')
underlines=${underlines%_}

E aqui está um método um pouco louco que não usa nenhum loop ou programa externo e deve funcionar em qualquer shell Bourne (pelo menos desde que set -f foi introduzido - embora a execução em um diretório vazio mitigue a falta de set -f ). Infelizmente, isso só funciona se a string não contiver espaços em branco.

set -f          # turn off globbing
IFS=$word       # split at any character in $word
set a $word     # split $word into one word between each character, i.e. empty words
shift           # remove the leading a (needed in case $word starts with -)
IFS=_
underlines=$*   # join the empty words, separated with the new value of $IFS

Uma variante mais complexa lida com espaço em branco, mas apenas se não houver sequência de espaços em branco consecutivos. Eu não acho que você pode ir mais longe com esse truque, já que as sequências de caracteres em branco em IFS são sempre reduzidas.

set -f
unset IFS; set a $0    # split at whitespace
IFS=$*; set $*         # split into empty words
IFS=_; underlines=$*   # collect the empty
    
por 15.05.2012 / 01:01
4

Em shells mais recentes, você pode fazer printf %s\n "${word//?/-}" . Eu não acho que o ksh88 tenha essa expansão em particular.

Se você não se importa com um processo extra, você pode fazer printf %s\n "${word}" | sed -e 's/./-/g' .

Sua abordagem também é boa, embora eu faça a seguinte pequena alteração:

print_underlined () {
        word=$1
        printf %s\n "$word"
        i=${#word}
        while (( i )); do
                printf -
                (( i = i - 1 ))
        done
        echo
}

E para uma abordagem completamente diferente, use a capacidade do terminal de exibir sublinhados reais, se disponíveis:

tput smul; printf %s\n "$word"; tput rmul

É claro que essa abordagem só funciona se você souber que o terminal em que o script é executado a suporta.

    
por 14.05.2012 / 15:23
1

Encontrei isso simplesmente pesquisando:

underline() { echo $1; echo "${1//?/${2:--}}";}

Basicamente a mesma coisa, mas muito mais compacta. Se você achar confuso, mais informações sobre a substituição das chaves podem ser encontradas aqui . Muito semelhante à sintaxe sed.

    
por 14.05.2012 / 15:41
1

Esta é uma maneira compatível com POSIX que funcionará no Solaris 10 & ksh88:

print_underlined () {
  printf "%s\n%s\n" "$1" $(printf "%s\n" "$1" | sed "s/./-/g")
}
$ print_underlined "hello world"
hello world
-----------
    
por 15.05.2012 / 04:11
-1
print_underlined () {

word=$1
tput smul
print $word
tput sgr0
}
    
por 09.04.2014 / 19:01