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: Sat, 31 Jan 2015 19:37:06 -0200
User-agent: Mozilla/5.0 (X11; Linux i686; rv:31.0) Gecko/20100101 Thunderbird/31.4.0

Olá Ronaldo, valeu a lembrança do set -x, realmente não lembrei de verificar 
com o debug.

Colei apenas as linhas referentes ao printf.
set -x
d1=4;d2=10;d3=5;m1=5;m2=3;m3=12;ano=2015
while read linha; do printf '%20s%02d/%02d/%d\n' $linha
done <<<"'Data: ' $d1 $m1 $ano
'Outra Data: ' $d2 $m2 $ano
'Mais uma data: ' $d3 $m3 $ano"
+ read linha
+ printf '%20s%02d/%02d/%d\n' ''\''Data:' \' 4 5 2015
              'Data:00/04/5
                201500/00/0
+ read linha
+ printf '%20s%02d/%02d/%d\n' ''\''Outra' Data: \' 10 3 2015
-su: printf: Data:: invalid number
              'Outra00/00/10
                   32015/00/0
+ read linha
+ printf '%20s%02d/%02d/%d\n' ''\''Mais' uma data: \' 5 12 2015
-su: printf: uma: invalid number
-su: printf: data:: invalid number
               'Mais00/00/0
                   512/2015/0

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

while read linha; do eval printf '%20s%02d/%02d/%d\\n' $linha
done <<<"'Data: ' $d1 $m1 $ano
'Outra Data: ' $d2 $m2 $ano
'Mais uma data: ' $d3 $m3 $ano"
+ read linha
+ eval printf '%20s%02d/%02d/%d\\n' ''\''Data:' \' 4 5 2015
++ printf '%20s%02d/%02d/%d\n' 'Data: ' 4 5 2015
              Data: 04/05/2015
+ read linha
+ eval printf '%20s%02d/%02d/%d\\n' ''\''Outra' Data: \' 10 3 2015
++ printf '%20s%02d/%02d/%d\n' 'Outra Data: ' 10 3 2015
        Outra Data: 10/03/2015
+ read linha
+ eval printf '%20s%02d/%02d/%d\\n' ''\''Mais' uma data: \' 5 12 2015
++ printf '%20s%02d/%02d/%d\n' 'Mais uma data: ' 5 12 2015
     Mais uma data: 05/12/2015


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


Abraços Paulo Bettega


On 31-01-2015 11:39, Ronaldo Ferreira de Lima address@hidden [shell-script] 
wrote:
> É possível verificar o que aconteceu usando o "modo debug" set -x, o
> grande problema foram os espaços "extras". Para evitar essas surpresas é
> recomendável utilizar o método tradicional:
>
> printf '%20s: %02d/%02d/%d\n' "$str" $dia $mes $ano
>
> []'s
> --
> "Não manejo bem as palavras
> Mas manipulo bem as strings."
> ------------------------------
> http://tecnoveneno.blogspot.com
>


On Sat, Jan 31, 2015 at 02:49:55AM -0200, Paulo Bettega address@hidden 
[shell-script] wrote:
 > Olá pessoal, tentei fazer esse loop, já que a linha do printf é sempre a 
mesma.
 > (Sei que nesse caso o loop é praticamente igual a escrever uma linha de
 > printf para cada linha do 'here strings', mas no futuro pretendo colocar
 > os dados num vetor).
 >
 > d1=4;d2=10;d3=5;m1=5;m2=3;m3=12;ano=2015
 > while read linha; do printf '%20s%02d/%02d/%d\n' $linha
 > done <<<"'Data: ' $d1 $m1 $ano
 > 'Outra Data: ' $d2 $m2 $ano
 > 'Mais uma data: ' $d3 $m3 $ano"
 >
 > A saída que eu queria era essa (talvez perca o alinhamento, os : são 
alinhados)
 > Data: 04/05/2015
 > Outra Data: 10/03/2015
 > Mais uma data: 05/12/2015
 >
 > mas o resultado foi esse
 > 'Data:00/04/5
 > 201500/00/0
 > bash: printf: Data:: invalid number
 > 'Outra00/00/10
 > 32015/00/0
 > bash: printf: uma: invalid number
 > bash: printf: data:: invalid number
 > 'Mais00/00/0
 > 512/2015/0
 >
 > Não entendi porque aconteceu isso, me pareceu tudo certo, pois o texto está
 > entre aspas simples, então o printf deveria reconhecer o texto todo como 
string %20s
 > e as três variáveis com a formatação da data %02d/%02d/%d
 >
 > Não sei porque, mas achei que o printf não estava recebendo a variável 
$linha como deveria,
 > então "chutei" um eval antes do printf, e o resultado foi animador:
 >
 > while read linha; do eval printf '%20s%02d/%02d/%d\n' $linha
 > done <<<"'Data: ' $d1 $m1 $ano
 > 'Outra Data: ' $d2 $m2 $ano
 > 'Mais uma data: ' $d3 $m3 $ano"
 > Data: 04/05/2015n Outra Data: 10/03/2015n Mais uma data: 05/12/2015n
 >
 > O resultado foi o que eu queria, apenas não quebrou a linha porque o \n
 > foi interpretado como "escapen", eu acho.
 > Então coloquei outro escape antes do \n e deu certo:
 >
 > while read linha; do eval printf '%20s%02d/%02d/%d\\n' $linha
 > done <<<"'Data: ' $d1 $m1 $ano
 > 'Outra Data: ' $d2 $m2 $ano
 > 'Mais uma data: ' $d3 $m3 $ano"
 > Data: 04/05/2015
 > Outra Data: 10/03/2015
 > Mais uma data: 05/12/2015
 >
 > Outro jeito que deu certo foi colocar apenas 'printf [formato]' entre aspas,
 > eval "printf '%20s%02d/%02d/%d\n'" $linha
 > ou
 > eval 'printf "%20s%02d/%02d/%d\n"' $linha
 >
 > No fim das contas o loop deu certo, mas eu não entendi porque.
 > Eu realmente achei que apenas colocando o printf dentro do loop teria que 
funcionar.
 > Porque o printf não reconhece direito a variável $linha sem o eval?



reply via email to

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