Loop for, problema em fazê-lo funcionar

Iniciado por Chernobyl_User, 06 de Junho de 2012, 19:29

tópico anterior - próximo tópico

Chernobyl_User

Olá, fiz um script para converter alguns arquivos mp3 para que tenham um tamanho menor, segue o script:

#!/bin/bash

#Pergunta pelos arquivos a converter
arquivos=$(zenity --file-selection --multiple --title "Selecione os arquivos que quer converter: " | tr '|' '\n')

#Pergunta pela pasta para por os arquivos convertidos
pasta=$(zenity --file-selection --directory --title "Selecione a pasta onde os arquivos deverão ser salvos: ")

#Conta o total de arquivos a converter
numarq=$(echo "$arquivos" | wc -l)

#Seta o numero base para a contagem
base=1

#Inicia o loop e converte os arquivos
for linha in "$arquivos" ; do

#Obtém o nome do arquivo a ser convertido
nome=$(echo "$linha" | rev | cut -d/ -f1 | rev)

echo "Convertendo arquivo "$base" de "$numarq": "$nome""
case $1 in
f) #Usa o ffmpeg para converter
ffmpeg -i "$linha" -acodec libmp3lame -ac 1 -ab 64k -y -ar 44100 "$pasta"/"$nome" &>> /dev/null
;;
l) #Usa o lame para converter
lame -m m -f -b 64 --cbr "$linha" "$pasta"/"$nome" &>> /dev/null
;;
*) echo "Encoder inválido!"
exit
;;
esac

#Muda o número do arquivo a converter
base=$(($base+1))
done

#Finaliza o programa
echo "Conversão completa!"

#Sai
exit


Ele devia funcionar assim:

1° Pelo terminal eu rodo: bash script.sh (l para o lame ou f para ffmpeg)
2º pede para selecionar os mp3 a converter
3° pede para escolher a pasta de saída
4° converte os arquivos selecionados e manda um output no terminal

O problema é que o laço for não está mandando os arquivos linha por linha para o encoder, ele está mandando tudo de uma vez só:

bash Dropbox/Scripts/mp3.sh l
Convertendo arquivo 1 de 2: musicaa 1.mp3 musica 2.mp3
Conversão completa!


Se eu selecionar só um arquivo, tudo funciona. Alguém tem alguma idéia?
Sony Vaio VPCEH30EB/W @ Ubuntu 12.04 + Ubuntu 12.10 + Debian 6.0

irtigor

É que você tem uma string. Trabalhe com um vetor

IFS=\| arquivos=($(zenity --file-selection --multiple --title "Selecione os arquivos que quer converter: "))
for i in "${arquivos[@]}"; do
    #faça alguma coisa o $i
done


Você pode traçar o que o script faz passando a opção "-x".

bash -x /caminho/para/o/script.sh

adri3d

sabe para que serve o caracter & em linhas como essa
ffmpeg -i "$linha" -acodec libmp3lame -ac 1 -ab 64k -y -ar 44100 "$pasta"/"$nome" &>> /dev/null

caso não saiba, aprenda vai ser util.

Chernobyl_User

Olá irtigor, adaptei sua dica para meu script e a saída do "bash -x" foi:

mp3.sh: linha 49: ${$arquivos[@]}: substituição incorreta

Citarsabe para que serve o caracter & em linhas como essa

ffmpeg -i "$linha" -acodec libmp3lame -ac 1 -ab 64k -y -ar 44100 "$pasta"/"$nome" &>> /dev/null

caso não saiba, aprenda vai ser util.

Seria o "&" do "&>> /dev/null? Pelo que eu sei, serve para redirecionar toda e qualquer saída de texto gerada pelo encoder para o lixo. O "&&" é o operador lógico "E".
Sony Vaio VPCEH30EB/W @ Ubuntu 12.04 + Ubuntu 12.10 + Debian 6.0

irtigor


zekkerj

Citarfor linha in "$arquivos" ; do
Acredito que vc colocou a variável entre aspas pra poder lidar com os nomes de arquivos com espaços, correto? Mas assim ele vai tratar todo o conteúdo da variável como uma string só.
Pesquise antes de perguntar, sua dúvida pode já ter sido respondida.
Não respondo dúvidas por MP, coloque sua dúvida no fórum onde ela pode ser pesquisada pelos seus colegas!
Não venha ao fórum apenas para perguntar. Se você sabe a resposta de um problema, porque não ajudar seu colega? ;D

fpissarra

#6
Citação de: Chernobyl_User online 07 de Junho de 2012, 23:21
Olá irtigor, adaptei sua dica para meu script e a saída do "bash -x" foi:

mp3.sh: linha 49: ${$arquivos[@]}: substituição incorreta

Talvez isso ajude:


OLDIFS=$IFS
IFS=$'|'
arquivos=$(zenity --file-selection --multiple)

for i in $arquivos; do
 // faz algo com $i aqui.
done

IFS=$OLDIFS


No post do irtigor, só faltou um salto de linha depois do ajuste da variável IFS.

irtigor

Não é necessário, do jeito que passei tem que funcionar, por isso pedi pra ver o código, ele errou ao copiar ou coisa do tipo.

fpissarra

Citação de: irtigor online 07 de Julho de 2012, 14:01
Não é necessário, do jeito que passei tem que funcionar, por isso pedi pra ver o código, ele errou ao copiar ou coisa do tipo.

Irtigor... Isso aqui:

IFS=\| arquivos=($(zenity --file-selection --multiple --title "Selecione os arquivos que quer converter: "))

Como está, com certeza não deve funcionar. Não, sem, pelo menos, um ponto-e-virgula depois de '|'.

irtigor

Funciona e é útil, por exemplo (nada de ponto e vírgula ou nova linha separando a variável)

echo $LANG
LANG=en_US.UTF-8 __aplicativo__ &
echo $LANG

Executa __aplicativo__ com a língua inglesa como padrão, como foi executado em subshell, a variável $LANG permanece com o valor anterior no shell atual.

fpissarra

Citação de: irtigor online 07 de Julho de 2012, 21:34
Funciona e é útil, por exemplo (nada de ponto e vírgula ou nova linha separando a variável)

echo $LANG
LANG=en_US.UTF-8 __aplicativo__ &
echo $LANG

Executa __aplicativo__ com a língua inglesa como padrão, como foi executado em subshell, a variável $LANG permanece com o valor anterior no shell atual.

Hummmmm.... interessante!

fpissarra

Citação de: irtigor online 07 de Julho de 2012, 21:34
Funciona e é útil, por exemplo (nada de ponto e vírgula ou nova linha separando a variável)

echo $LANG
LANG=en_US.UTF-8 __aplicativo__ &
echo $LANG

Executa __aplicativo__ com a língua inglesa como padrão, como foi executado em subshell, a variável $LANG permanece com o valor anterior no shell atual.
De fato, é um recurso interessante... mas o IFS só será setado na execução do zenity, não? O loop for continuará separando as strings por espaços, tabs e \n...

irtigor

Usei um array, tanto faz o IFS depois, mas sim no bash só é alterado pro comando.
CitarIFS=\| arquivos=($(zenity --file-selection --multiple --title "Selecione os arquivos que quer converter: "))

fpissarra

Citação de: irtigor online 08 de Julho de 2012, 16:26
Usei um array, tanto faz o IFS depois, mas sim no bash só é alterado pro comando.
CitarIFS=\| arquivos=($(zenity --file-selection --multiple --title "Selecione os arquivos que quer converter: "))
Ops! É mesmo! Sorry... ficou legal!