Programando Shell Script - Parte 2

Started by Anonymous, 24 de April , 2007, 09:55:32 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Anonymous

Continuando o Tópico do Bloodrain  "Programando Shell Script"

Criando interfaces no Kommander

O Kommander permite criar interfaces gráficas para shell scripts, usando a biblioteca Qt do KDE. Ele é dividido em duas partes, o kmdr-editor é o editor que permite criar as interfaces, enquanto o kmdr-executor executa os arquivos gerados por ele.

Ao instalar o pacote do Kommander você obtém os dois componentes. Nas distribuições derivadas do Debian você pode instala-lo com um "apt-get install kommander". Pacotes rpm para várias distribuições podem ser encontrados no http://www.rpmfind.net/

Em último caso, você pode baixar uma versão genérica no: http://kde-apps.org/content/show.php?content=12865

A interface do kmdr-editor lembra um pouco a do VB ou Delphi, mas é mais simples por conter muito menos funções. Lembre-se que o objetivo do kommander é desenvolver interfaces para scripts, ele provê poucas funções por sí só.

Ao criar um novo projeto, no Arquivo > Novo você tem a opção de criar um diálogo ou um assistente. Um diálogo cria uma interface simples, com botões e abas, do tipo onde você escolhe entre um conjunto de opções e clica no Ok para acionar o script. Já o assistente permite criar uma seqüência de telas interligadas, útil para criar programas de instalação por exemplo.

Os arquivos gerados no kmdr-editor não são binários, mas sim arquivos em xml, que são interpretados e executados pelo kmdr-executor. Estes arquivos contém os "fontes" da interface. Não é possível criar diretamente um binário através do kommander, sempre é necessário ter o kmdr-executor para executar os arquivos xml.

Você pode ver os fontes do Painel de Controle do Kurumin, junto com outros painéis que desenvolvi usando o Kommander dentro da pasta /etc/Painel no Kurumin.

Vamos a um exemplo rápido. Que tal criar uma interface mais amigável para aquele script para gravar programas de TV que havíamos criado usando o kdialog? Usando o kommander poderíamos criar uma interface muito mais elaborada e profissional para ele.

Abra o kmdr-editor e crie um diálogo:


Vou criar um script simples, com um conjunto de opções para escolher o canal, tempo de gravação e o arquivo que será criado, que armazenarão as informações em um conjunto de variáveis e um botão que executa o script principal, montando o comando do mencoder. Para dificultar um pouco, vou acrescentar mais uma opção, que permite escolher a qualidade da gravação.

Para as opções de escolha do canal e tempo de gravação, vou usar o widget "Line Edit", que cria uma linha editável. Vou usar dois, um para cada opção, junto com dois "TextLabel", duas legendas simples em texto.

Você pode escolher o texto padrão das opções dando um duplo clique sobre elas. Na janela de propriedades você pode configurar opções como o tipo e tamanho das fontes, cores, alinhamento do texto, etc. Estas opções mudam de acordo com o widget usado.

Por enquanto não estou me preocupando com o visual, apenas em adicionar as opções. É mais fácil se preocupar primeiro com a parte técnica e deixar para cuidar da parte visual depois que o script estiver funcionando.



O texto dentro das duas caixas precisa ser armazenado em variáveis para que possamos utilizá-los mais tarde dentro do script principal. Para que isso aconteça, clique com o botão direito sobre cada uma das caixas e acesse a opção "Edit Text Associations". No campo, digite "@widgetText".



Isso faz com que o kommander crie uma variável contendo o texto digitado dentro da caixa. Esta variável tem o mesmo nome do widget, nome este que você escolhe nas propriedades. Para facilitar a minha vida depois, vou nomear as duas caixas como "canal" e tempo", indicando exatamente o que ambas fazem:



É preciso incluir também um widget para salvar o arquivo. O Kommander oferece uma função bem similar ao --getsavefilename do kdialog, o widget "File Selector". Adicione um no programa, como fizemos com as duas caixas de texto.

O File Selector pode ser usado para abrir um arquivo, escolher uma pasta ou salvar um arquivo. Precisamos indicar a função do nosso nas propriedades. Para isso, configure a opção "selectionType" como "Save" (indicando que a janela servirá para salvar um arquivo).

Veja que aproveitei também para configurar a opção "selectionFilter" como "*.avi *.mpg *.wmf", que faz com que a janela do gerenciador de arquivos mostre apenas arquivos de vídeo, com as três extensões expecificadas e salve os arquivos com a extenção .avi, mesmo que o usuário não especifique a extensão. A opção "selectionCaption" permite escolher o título da janela para salvar.



Não se esqueça de configurar a opção "Edit Text Associations" do widget como "@widgetTex" como fizemos com as duas caixas de texto e escolher um nome nas propriedades. No meu caso deixei o nome como "arquivo".

Você pode ver um preview da interface que está editando clicando no Visualização > Preview Form. Isto é perfeito para ir testando cada opção conforme for adicionando, sem deixar que os erros se acumulem.

Falta incluir a opção para escolher a qualidade de gravação, dois parâmetros que podem ser especificados na linha de comando do mencoder. Vou criar dois botões separados, uma para escolher a resolução do vídeo (640x480 ou 320x240) e escolher o bitrate, que determina a qualidade e tamanho final do arquivo.

No caso da resolução vou oferecer apenas duas opções, por isso vou usar o widget "RadioButton", criando dois botões. Estes botões precisam ser exclusivos, ou seja, apenas um deles pode ser selecionado de cada vez. Para isso, vou precisar colocá-los dentro de um "ButtonGroup", outro widget, que permite agrupar vários botões, para fazê-los se comportarem da forma desejada.

Isto já vai envolver um número maior de passos. Primeiro crie o ButtonGroup do tamanho desejado e coloque dois botões dentro dele. Nas propriedades, escolha nomes para os três. No meu caso coloquei "resolucao" (para o ButtonGroup), resoluçao1 e resolucao2 para os botões.

Nas propriedades do ButtonGroup, configure a opção "RadioButtonExclusive" como "Verdadeiro". Isso faz com que apenas um dos botões dentro dele possa ser marcado de cada vez.

Dentro das propriedades do primeiro botão, deixe a opção "Checked" como "Verdadeiro". Isso faz com que ele fique marcado por padrão. Lembre-se que ao desenvolver uma interface é importante fazer com que todas as opções sempre tenham algum valor padrão, isso diminui a possibilidade de erros por parte do usuário, já que o script vai funcionar mesmo que ele não configure todas as opções.



Falta agora configurar o "Edit Text Associations" dos dois botões, para armazenar o conteúdo da variável que será criada caso cada um deles seja pressionado. Desta vez não vou usar o "@WidgetText" pois os botões não contém texto algum. Vou indicar manualmente um valor padrão para cada um dos dois botões.

Um deles conterá o valor "width=640:height=480" e o outro terá o valor "width=320:height=240", que são as opções que poderá ser incluídas na linha de comando do mencoder que será criada ao executar o programa. Lembre-se que apenas um dos dois botões pode ser marcado de cada vez, por isso apenas uma das duas opções será usada.



Os dois botões estão dentro do ButtonGroup e apenas um deles pode ser marcado de cada vez. O valor da váriavel do ButtonGroup ("resolucao" no meu caso) passa a ser o valor padrão do botão que for selecionado. Ou seja, se for marcado o primeiro botão, a variável "resolucao" receberá o valor "width=640:height=480".

Para que isso funcione, preciso configurar o "Edit Text Associations" do ButtonGroup como "@widgetTex".

Na hora de usar a variável, uso a variável "resolucao", correspondente ao ButtonGroup e não as variáveis dos botões.

Esta é a moral da história de usar o ButtonGroup ao invés de botões isolados. Você pode colocar vários botões dentro dele, fazer com que apenas um botão possa ser clicado de cada vez, determinar um valor padrão para cada botão e fazer com que a variável do ButtonGroup contenha apenas o valor do botão que foi selecionado.

Para escolher o bitrate que será usado ao gerar o arquivo, vou usar um "SpinBoxInt", um widget que cria uma caixa onde você pode escolher um valor numérico usando duas setas. Nas propriedades, você escolhe um valor máximo, um valor mínimo, um valor padrão e o "lineStep", que determina quanto o número aumenta ou diminui cada vez que um dos botões é pressionado.

No "Edit Text Associations" do SpinBox, coloque "@widgetTex", como sempre. Isso faz com que a variável contenha o número escolhido. Não se esqueça de escolher um nome para ele nas propriedades. No meu caso escolhi "bitrate".

Para melhorar o visual, coloquei o SpinBox dentro de um "GroupBox", que cria um quadrado, similar ao ButtonGroup, mas com função puramente estética.



Como disse acima, o bitrate determina a qualidade do vídeo gerado, especificando o número de kbits que serão reservados para cada segundo de vídeo. Um bitrate de 1500 kbits gera arquivos com cerca de 11 MB por minuto de vídeo, quase 700 MB por hora. O tamanho do arquivo aumenta ou diminui proporcionalmente de acordo com o bitrate. Um bitrate muito alto resultaria num arquivo gigantesco e um muito baixo resultaria num arquivo tosco, com uma qualidade muito ruim. Por isso usamos o SpinboxInt para determinar uma margem de valores razoáveis.

Você poderia adicionar mais um SpinBoxInt para oferecer também a opção de alterar o bitrate do som, mas no meu caso não vou incluir isto, por o som compactado em MP3 representa uma percentagem pequena do tamanho do arquivo.

Depois dessa trabalheira toda, temos as variáveis: canal, tempo, arquivo, resolucao e bitrate, que usaremos para gerar a linha de comando.

Precisamos agora de um gatilho, um botão que executa o comando final. Vamos usar um simples "ExecButton".

Dentro do "Edit Text Associations" do botão, vão as linhas:
Quoteverificador="@arquivo"
if [ -z "$verificador" ];
then
kdialog --msgbox "Você esqueceu de indicar o arquivo onde o vídeo será salvo ;-)"
exit 0
fi



kdialog --title "Gravando" --passivepopup "Gravando o canal $var1
por: @tempo horas
no arquivo: @arquivo

Feche a janela de terminal para abortar" 6 &

xterm -e "mencoder tv:// -tv driver=v4l2:input=0:normid=4:channel=@canal:chanlist=us-bcast:
@resolucao:device=/dev/video0:adevice=/dev/dsp0:audiorate=48000:
forceaudio:forcechan=2:buffersize=64
-quiet -oac mp3lame -lameopts preset=medium -ovc lavc -lavcopts
vcodec=mpeg4:vbitrate=@bitrate:keyint=132 -vop pp=lb -endpos
@tempo -o @arquivo "

kdialog --title "Gravar-TV" --passivepopup "Ok!
A gravação terminou." 5 &

Veja que são os mesmos comandos que usamos no primeiro script, foi precisa apenas adaptar o uso das variáveis. Num script em shell normal as variáveis são identificadas por um dólar, "$", enquanto as variáveis criadas através da interface no Kommander são identificadas por uma arroba, "@".

A função que acrescentei no início do arquivo verifica se foi escolhido o arquivo onde salvar o arquivo, a variável "@arquivo" do Kommander. As funções condicionais do bash (if, case, etc.) não entendem as variáveis do Kommander diretamente, por isso precisei primeiro criar a variável "verificador", com o conteúdo da variável @arquivo do Kommander.

O "-z" é um comparador, significa "é nula", ou seja, ela serve para verificar se a variável está vazia. Caso esteja, é exibida uma mensagem na tela e o script é fechado, graças ao "exit 0". Como o script é executado pela janela principal do Kommander, o script fecha, mas a janela principal continua aberta.



Você pode usar funções do Kdialog, funções lógicas e outros comandos que usaria num script tradicional. O Kommander apenas acrescenta algumas possibilidades novas.

Depois de revisar tudo, você pode finalmente testar o programa, executando-o no kmdr-executor:

$ kmdr-executor gravar-tv.kmdr
A segunda parte do trabalho envolve dar uma melhorada no aspecto visual. Você pode acrescentar imagens e ícones usando o widget "PixmapLabel".

Os ícones do sistema vão por padrão dentro da pasta /usr/share/icons, e são um bom ponto de partida. Você pode usar também imagens e ícones personalizados, salvos em .png. Todas as imagens usadas são salvas como parte do arquivo, como se fosse um documento do OpenOffice, você não precisa se preocupar em distribuir as imagens junto com o programa, a única dependência é o kmdr-executor, junto com os comandos usados dentro do script

A maioria dos widgets, como as etiquetas de texto, caixas, etc. Possuem várias opções de cores e fontes dentro das propriedades, que permitem fazer um bom trabalho. Esta é a versão final do script, que desenvolvi para uso no Kurumin:



Outro recurso interessante do Kommander e vem sendo melhorado rapidamente nas novas versões são as conexões. Elas permitem adicionar elementos dinâmicos na interface, um textLabel cujo conteúdo muda quando você clica num botão ou mostra informações sobre um arquivo escolhido num File Selector e assim por diante.

As conexões ainda são um recurso incipiente, a cada nova versão do Kommander muita coisa muita, novas opções são adicionadas, etc. Por isso, vou dar apenas uma introdução e deixar para explicar com mais profundidade numa futura atualização deste texto.

Para seguir este exemplo, você precisa estar usando o Kommander 1.0 Final ou mais recente.

Vamos usar algumas conexões para criar um editor de imagens primitivo. Comece criando um novo projeto e desenhe uma interface contendo um FileSelector, um textLabel, um PixmapLabel e quatro botões que usaremos para adicionar algumas funções de edição. Por enquanto não incluí código algum, apenas desenhei os widgets:



O objetivo é fazer com que o arquivo de imagem escolhido no FileSelector seja exibido no PixmapLabel, ao mesmo tempo em que a localização e nomes completos do arquivo são mostrados no textLabel. As duas coisas atualizadas automaticamente, sem que seja necessário pressionar nenhum botão.

Os botões vão conter mais algumas funções estáticas para deletar a imagem, girar e limpar os dois campos (novamente usando conexões).

Vamos começar fazendo com que a imagem seja exibida no PixmapLabel. Procure a ferramenta de conexão na interface principal. Clique primeiro sobre o FileSelector e arraste até o PixmapLabel. Isso cria uma conexão entre eles



Na janela de propriedades que será aberta, você verá duas janelas, uma com os sinais disponíveis no FileSelector e do outro lado as propriedades do PixmapLabel que podem ser alteradas através deles.

Marque a opção "widgetTextChanged(const QString)" do lado do FileSelector e a opção "setWidgetText(const QString)" do lado do PixmapLabel. Clique no "Conectar" para efetivar a conexão:



O que fizemos aqui foi especificar que quando o texto dentro do FileSelector for mudado (ou seja, quando for escolhido algum arquivo) o conteúdo do PixmapLabel muda, exibindo o conteúdo do arquivo. Se fosse uma caixa de texto, seria mostrado o conteúdo do arquivo na forma de texto, mas como estamos usando uma caixa de imagem, será mostrado um preview da imagem.

Crie agora uma nova conexão, ligando o FileSelector e o textLabel. Na janela de propriedades, marque a opção "widgetTextChanged(const QString)" para o FileSelector (o mesmo do passo anterior) e a opção "Populate()" para o textLabel.



O textLabel está originalmente vazio, sem conteúdo algum. A função Populate vai "populá-lo" (piadinha infame :-P) com o resultado de um comando que definiremos no passo a seguir. Isso é disparado sempre que o conteúdo do FileSelector muda. Sempre que é escolhido um arquivo diferente, o comando é executado novamente e o conteúdo do textLabel muda.

Para definir o comando, clique com o botão direito sobre o textLabel e acesse a opção "Editar texto do Kommander". Dentro da janela, acesse a opção "Texto para: Population" que está no canto superior direito.



O comando começa com "@exec" com o comando propriamente dito entre parênteses. Dentro dos parênteses você pode separar uma seqüência de comandos por ponto e vírgula, usar o pipe e outros componentes de um shell script normal.

Neste exemplo, estou usando o comando:

Quote@exec(identify "@arquivo.text" | cut -d " " -f 2-10)

O identify é um comando de texto que exibe as propriedades da imagem, como formato e resolução. Nas propriedades do meu FileSelector mudei o nome para "arquivo", logo o @arquivo.text se refere ao conteúdo do FileSelector, ou seja, o nome do arquivo que foi escolhido. O "| cut -d " " -f 2-10" é opcional, ele serve apenas para "limpar" a saída do identify, retirando o nome do arquivo.

Salve o arquivo e clique no Executar > Executar diálogo para ver um preview dele funcionando. Veja que ao escolher um arquivo de imagem no FileSelector a imagem é realmente exibida no PixmapLabel, enquanto o textLabel mostra as informações fornecidas pelo identify:



Apesar disso, ainda existe um pequeno bug, está sendo exibido apenas um pedaço da imagem. Para que seja exibido um preview reduzido da imagem, acesse as propriedades do PixmapLabel e mude a opção "scaledContents" para verdadeiro (true). A partir daí a imagem passa a ser redimensionada corretamente.



Falta agora só dar funções aos botões de edição, que é a parte mais fácil.

Dentro do botão "Deletar a imagem" (botão direito > Editor texto do Kommander) inclua a função:

Quotekdialog --yesno "Tem certeza?"
retval=$?
if [ "$retval" = "0" ]; then
rm -f @arquivo.text
fi

Nos botões Girar no sentido horário e girar no sentido anti-horário, inclua (respectivamente) as funções:

Quotejpegorient +90 @arquivo.text

jpegorient +270 @arquivo.text

O jpegorient é mais um comando de edição de imagem em modo texto, que faz parte do imageMagik. Ele permite justamente girar a imagem no sentido desejado, é muito usado em scripts.

O último botão, Limpar, vai servir apenas para limpar o conteúdo do PixmapLabel e do textLabel. Para isso, crie uma conexão entre o botão e o PixmapLabel. Marque de um lado a opção "Pressed" e do outro a opção "clear()". Faça o mesmo entre ele e o textLabel.



Nosso programinha está quase pronto, existe apenas um último "bug": ao clicar nos botões de girar, a imagem é alterada, mas não é automaticamente atualizada na janela do programa.

Se você for perfeccionista e quiser resolver isso, crie uma conexão entre cada um dos dois botões de girar e o PixmapLabel. Marque a opção "Pressed()" para o botão e "Populate()" para o PixmapLabel.



Acesse agora as propriedades do PixmapLabel e, dentro do "Texto para: Population" coloque "@arquivo.text". Isso fará com que cada vez que um dos dois botões for pressionado, a nova conexão dispare uma atualização da imagem:



Você pode baixar o arquivo do programa pronto (5 KB) aqui:
http://www.guiadohardware.net/kurumin/P ... mplo2.kmdr

O manual oficial do Kommander está disponível no:
http://www.kde.me.uk/kommander-tutorial ... docs-html/

Este artigo do Linux.com contém várias dicas e exemplos:
http://applications.linux.com/applicati ... =26&tid=47

Este tutorial é dividido em três partes. Na terceira parte veremos como usar os servicemenus do KDE e mais dicas de como criar scripts de configuração.


Créditos: Morimoto (GuiadoHardware)


Ps: Dá mo trabalho Ctrl+C/Ctrl+V aff² =x, mais tá ai espero que ajude ^^

jedi

nossaaa...

q showw....
mandou bem, ta muito loko, vou ler depois com mais tempo
os detalhes e tals

flw...
emo

Anonymous

Muito interessante Shell Script, pena que não da muita grana, por não ser muito utilizado no mundo capitalista...Uma linguagem pratica e com muitas utilidades, e "Sem Pau, Erro, Tela Azul".