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: Paulo Bettega
Subject: Re: [shell-script] printf em um loop while só funcionou com eval
Date: Sun, 01 Feb 2015 12:27:12 -0200
User-agent: Mozilla/5.0 (X11; Linux i686; rv:31.0) Gecko/20100101 Thunderbird/31.4.0

Olá Ronaldo, obrigado pelos exemplos.
Também achei que usar eval seria um exagero, mas pelo jeito eu estava
preso no modelo que tinha imaginado. Vou tentar usar algum dos teus exemplos.

Só como curiosidade, lembrei de tirar os apóstrofos do texto e usar um escape
nos espaços. Se fosse usar essa solução, teria que processar o texto e
substituir <espaço> por <\espaço> com um sed talvez, sed 's/ /\\ /g' 
<<<"$texto".

Interessante que escapando os espaços, o debug mostra a linha do printf bem
mais simples, sem tantos apóstrofos, e funciona sem usar eval.

Com apóstrofos:
while read l1 l2 l3 l4; do printf '%20s: %02d/%02d/%d\n' "$l1" $l2 $l3 $l4
done <<<"Data $d1 $m1 $ano
'Outra Data' $d2 $m2 $ano
'Mais uma data' $d3 $m3 $ano"
+ read l1 l2 l3 l4
+ printf '%20s: %02d/%02d/%d\n' Data 4 5 2015
                Data: 04/05/2015
+ read l1 l2 l3 l4
+ printf '%20s: %02d/%02d/%d\n' ''\''Outra' 'Data'\''' 10 3 2015
-su: printf: Data': invalid number
              'Outra: 00/10/3
                2015: 00/00/0
+ read l1 l2 l3 l4
+ printf '%20s: %02d/%02d/%d\n' ''\''Mais' uma 'data'\''' 5 12 2015
-su: printf: uma: invalid number
-su: printf: data': invalid number
               'Mais: 00/00/5
                  12: 2015/00/0


Escapando os espaços, a linha do printf fica como "deveria ser":
while read l1 l2 l3 l4; do printf '%20s: %02d/%02d/%d\n' "$l1" $l2 $l3 $l4
done <<<"Data $d1 $m1 $ano
Outra\ Data $d2 $m2 $ano
Mais\ uma\ data $d3 $m3 $ano"
+ read l1 l2 l3 l4
+ printf '%20s: %02d/%02d/%d\n' Data 4 5 2015
                Data: 04/05/2015
+ read l1 l2 l3 l4
+ printf '%20s: %02d/%02d/%d\n' 'Outra Data' 10 3 2015
          Outra Data: 10/03/2015
+ read l1 l2 l3 l4
+ printf '%20s: %02d/%02d/%d\n' 'Mais uma data' 5 12 2015
       Mais uma data: 05/12/2015


Abraços Paulo Bettega



On 31-01-2015 21:41, Ronaldo Ferreira de Lima address@hidden [shell-script] 
wrote:
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


----------------------------------------------------------------------------------------------------
Enviado por: Ronaldo Ferreira de Lima <address@hidden>


reply via email to

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