shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script] printf em um loop while só funcionou com eval


From: Ronaldo Ferreira de Lima
Subject: Re: [shell-script] printf em um loop while só funcionou com eval
Date: Sat, 31 Jan 2015 21:41:10 -0200
User-agent: mutt-ng/devel-r804 (Linux)

On Sat, Jan 31, 2015 at 07:37:06PM -0200, Paulo Bettega address@hidden 
[shell-script] wrote:
> Olá Ronaldo, valeu a lembrança do set -x, realmente não lembrei de verificar 
> com o debug.
[...]
> Parece que o shel adiciona alguns apóstrofos, e os apóstrofos que eu coloquei
> pra proteger o texto acho que são os que aparecem escapados.
>
> Com eval e o \n escapado dá pra ver que o shell monta a linha
> como eu imaginei sem o eval: printf '%20s%02d/%02d/%d\n' 'Data: ' 4 5 2015
Precisa  fazer muito  malabarismo para  garantir que  os parâmetros  com
espaços  sejam tratados  adequadamente para  quando finalmente  chegarem
para o  printf processar sem falar  que dependendo do conteúdo  da linha
poderia ser quase impossível garantir  que esses parâmetros chegassem em
condições  de serem  interpretados sem  erros. Seguindo  este caminho  e
assumindo  que  sempre  a  linha  terminha com  uma  sequência  de  três
argumentos  numéricos  seria  até  melhor usar  expressões  regulares  e
capturar as backreferences como no exemplo abaixo com o bash:

d1=4;d2=10;d3=5;m1=5;m2=3;m3=12;ano=2015
while IFS=$'\n' read linha; do
    [[ "$linha" =~ ^(.*)\ ([0-9]+)\ ([0-9]+)\ ([0-9]+)$  ]]
    printf '%20s: %02d/%02d/%d\n' "${BASH_REMATCH[1]}" ${BASH_REMATCH[@]:2}
done <<<"Data $d1 $m1 $ano
Outra Data $d2 $m2 $ano
Mais uma data $d3 $m3 $ano"

> Aqui vai um esboço do script. O número de linhas que serão impressas pode
> variar, por isso pensei em colocar o printf dentro do loop.
>
> Além disso o alinhamento do texto deve ser conforme a variável $texto mais 
> longa.
> (aqui teve outro problema. As outras linhas ficavam dois caracteres 
> desalinhadas
> com a linha mais longa. Somando dois na $tabulacao resolveu).
> Pensei nisso mais como um exercício, mas no fim das contas ficou bem mais
> complicado do que eu achei que ficaria.
>
> #!/bin/bash
>
> tabulacao=1
> datas=()
> while true; do
>          read -p "Texto: " texto
>          # Guarda o maior comprimento de $texto para usar
>          # como alinhamento no printf.
>          [ "${#texto}" -gt "$tabulacao" ] && tabulacao=$((${#texto}+2))
>          [ "$texto" = 'fim' ] && break
>          texto="$texto: "
>          read -p "Dia: " dia
>          read -p "Mês: " mes
>          read -p "Ano: " ano
>          datas=( "${datas[@]}" "'$texto' $dia $mes $ano" )
> done
>
> for i in $(seq ${#datas[*]}); do
>          eval 'printf "%${tabulacao}s%02d/%02d/%d\n"' ${datas[$((i-1))]}
> done
Daria para armazenar as variáveis pré-formatadas no array e preocupar-se
com alinhamento apenas no final, esquecendo do eval inclusive:

o conteúdo do while pode ser modificado para:

    read -p "Texto: " texto
    read -p "Dia: " dia
    read -p "Mês: " mes
    read -p "Ano: " ano

    [ "$texto" = 'fim' ] && break

    fmt_str=$(printf '%s: %02d/%02d/%d' "$texto" $dia $mes $ano)
    datas[${#datas[@]}]=$fmt_str
    [ ${#fmt_str} -gt $tabulacao ] && let tabulacao=${#fmt_str}+2

e a formatação no final para:

    for (( i = 0; i <= ${#datas[*]}; i++ )); do
        printf "%${tabulacao}s\n" "${datas[$i]}"
    done

É melhor deixar o eval para os casos onde não é possível "fugir" dele.

> Abraços Paulo Bettega

[]'s
--
"Não manejo bem as palavras
Mas manipulo bem as strings."
------------------------------
http://tecnoveneno.blogspot.com


reply via email to

[Prev in Thread] Current Thread [Next in Thread]