Arquivo de configuração do OpenSSH

Apenas hoje descobri o arquivo de configurações do OpenSSH, que podemos utilizar para definir alguns atalhos na hora de realizar conexões. Se você sempre se conecta ao servidor meu.exemplo.com.br, com o usuário joao, por exemplo, a forma tradicional de se conectar é a seguinte:

ssh joao@meu.exemplo.com.br

Convenhamos, isso é bem chato de escrever. Não foi à toa que os criadores do OpenSSH definiram uma solução um tanto quanto óbvia para resolver esse problema: um arquivo de configurações para cada usuário (além do arquivo de configurações globais).

Para o nosso exemplo, conseguiríamos reduzir o comando para o seguinte:

ssh exemplo

Para isso bastaria criar um arquivo ~/.ssh/config com o seguinte conteúdo:

Host exemplo
  HostName meu.exemplo.com.br
  User joao

A transferência de arquivos também pode fazer uso do novo nome:

scp dados.tgz exemplo:~

Você pode criar regras muito mais elaboradas, mas no meu caso não preciso de muito mais que isso. Para maiores informações sobre a sintaxe do arquivo de configuração e sobre todas as opções possíveis consulte o manual:

man ssh_config

Bash One Liners #3

Em: 26/06/2008 Tags: awk, Bash Comentários (0) Referencie do seu blog (Trackback)

Em Bash One Liners #2 apresentei uma combinação de programas Linux para construirmos um ranking dos meses com mais artigos publicados em um blog. Com um pouco mais de esforço podemos calcular o somatório e a média de artigos publicados durante a vida do blog. É o que vamos ver agora.

Vamos começar com o seguinte arquivo (o ranking do meu blog antes de postar este artigo):

14 Fevereiro 2008
12 Novembro 2007
9 Janeiro 2008
8 Setembro 2007
7 Junho 2008
6 Dezembro 2007
5 Outubro 2007
5 Maio 2008
3 Março 2008
2 Julho 2007
2 Agosto 2007
1 Abril 2008

Supondo que esse conteúdo esteja no arquivo `ranking’, o seguinte one liner nos dá o total de artigos publicados:

awk '{ sum += $1 } END { print sum }' ranking

E para termos a média:

awk '{ sum += $1 } END { print sum / NR }' ranking

Nem precisamos de pipes desta vez. No primeiro script utilizamos a variável sum para armazenar o somatório da primeira coluna de dados do arquivo. O awk não se incomoda com variáveis não inicializadas, e é isso que nos permite fazer a totalização com um único comando. A cláusula END é especial, pois é executada apenas quando todas as linhas do arquivo já foram avaliadas. Para programas como esse que geram relatórios, essa é a parte ideal para imprimir o rodapé ou algum tipo de totalização. É exatamente isso que fazemos.

O segundo script é idêntico ao primeiro, com a exceção de que imprime a divisão do somatório pela quantidade de linhas analisadas. Na verdade NR, quando utilizado fora da cláusula END, guarda sempre o número da linha corrente, mas como estamos dentro de END ela guarda o número da última linha lida, que é exatamente o total de linhas analisadas.


Bash One Liners #2

Em: 26/06/2008 Tags: sed, sort, awk, Bash Comentários (1) Referencie do seu blog (Trackback)

Este segundo episódio da série apresenta um one liner que imprime o ranking de meses com mais artigos publicados em um blog (e uma explicação detalhada de como o one liner foi construído, para que o leitor conheça mais as ferramentas que qualquer distribuição Linux nos dá de graça e muitas vezes nem sabemos que existem).

Este script funciona apenas para blogs que tenham uma listagem de artigos mais publicados com a seguinte estrutura geral (esse padrão pode se repetir várias vezes):

mês ano_com_quatro_dígitos (quantidade_de_artigos)

Para este artigo utilizo como exemplo o blog da Thânia Clair, pois se eu utilizar o meu, após publicado o artigo as expressões regulares utilizadas passam a casar com as listagens deste artigo, e todos os exemplos passam a apresentar resultados diferentes dos que eu obtive antes da publicação.

Eis o one liner:

w3m -dump http://www.thaniaclair.com | awk '/[0-9][0-9][0-9][0-9] \([0-9]+\)$/ { print $4, $2, $3 }' | sed 's/[\(|\)]//g' | sort -gr

Eis o resultado:

23 Janeiro 2008
18 Dezembro 2007
16 Fevereiro 2008
13 Novembro 2007
6 Abril 2008
5 Março 2008
2 Maio 2008
1 Junho 2008

Não parece muito simples de entender, né? Não se preocupe, vou apresentar aqui, passo a passo, como cheguei a essa solução. Considero esse um exemplo significativo de one liner, pois demonstra a filosofia que tenho seguido para criar minhas soluções: escolher a ferramenta mais adequada para a tarefa. Note que utilizei 4 programas para chegar a esse resultado, em vez de uma única linguagem de programação, ao contrário do que nos ensinam em cursos Brasil afora.

Estes 4 programas têm propósitos bem específicos, e por isso atendem tão bem ao domínio do meu problema:

  • w3m: navegador web modo texto, com suporte a screen scraping
  • awk: linguagem criada para processamento de dados estruturados
  • sed: linguagem criada para transformação de texto
  • sort: programa criado para ordenar linhas de um arquivo

Como sugestão, proponho ao leitor realizar a mesma tarefa com uma linguagem de programação de propósito geral, como Perl, PHP, Python ou Ruby, e depois me contar em quantas linhas resolveu o mesmo problema (ouso chutar que Ruby e Perl gastariam menos linhas). Só pra não perder a deixa: tente em Java também!

Obviamente, não tenho nada contra nenhuma dessas linguagens, estou apenas reforçando a minha fisolofia da melhor ferramenta para o trabalho.

Agora vamos à solução.

Passo 1 - Imprimir o conteúdo do site

Para imprimir o conteúdo de um site na saída padrão a opção mais simples que eu conheço é utilizar ou o lynx ou o w3m com a opção -dump habilitada. O conteúdo é impresso em um formato estruturado, mas todas as tags são removidas. O seguinte comando:

w3m -dump http://www.thaniaclair.com

Imprimiria um documento que terminaria assim (estou suprimindo caracteres especiais que só fazem sentido quando lidos em um terminal):

  ruby (6)
  tirinhas (21)
  web (1)

Arquivos

  Junho 2008 (1)
  Maio 2008 (2)
  Abril 2008 (6)
  Março 2008 (5)
  Fevereiro 2008 (16)
  Janeiro 2008 (23)
  Dezembro 2007 (18)
  Novembro 2007 (13)

Nosso próximo passo é filtrar esse documento, para trabalhar apenas com as linhas que nos interessam. Nesse ponto entra o awk.

Passo 2 - Selecionar as linhas que interessam com awk

As linhas que nos interessam são todas aquelas que exibem a quantidade de artigos publicados durante cada mês de vida do blog. Essas linhas seguem o mesmo padrão: o nome de um mês, seguido de um espaço em branco, seguido de um ano, seguido de um espaço em branco, seguido pelo número de artigos entre parênteses.

A função do awk, nesse momento, é varrer todo o documento impresso pelo w3m, e desse documento excluir todas as linhas que não se enquadrem nesse padrão. Nossa declaração (na forma de uma expressão regular) é a seguinte: imprima qualquer linha que termine com 4 números (o ano), seguido por um espaço em branco, seguido por um ou mais números (a quantidade de artigos) cercados por parênteses, caso tudo isso esteja no fim da linha.

awk '/[0-9][0-9][0-9][0-9] \([0-9]+\)$/ { print $0 }'

O awk, então, imprimiria:

Junho 2008 (1)
Maio 2008 (2)
Abril 2008 (6)
Março 2008 (5)
Fevereiro 2008 (16)
Janeiro 2008 (23)
Dezembro 2007 (18)
Novembro 2007 (13)

Ótimo! Apenas as linhas que nos interessam. Mas como vamos ordenar esses dados? Como sabemos de antemão que o programa que irá ordená-los será o sort (e que o sort ordena as linhas lendo-as da esquerda para a direita), temos que posicionar a quantidade de artigos do mês no início da linha, e não no final. Nosso texto precisa, portanto, de transformação. Mas essa transformação é trivial para o awk. Vamos ver porquê.

No momento em que o awk encontra uma linha que atende ao padrão que especificamos ele define um conjunto de variáveis iniciadas por $. $0 corresponde à própria linha; para definir as demais variáveis $ o awk utiliza (por padrão) o espaço em branco como caracter divisor de dados, e atribui cada dado a uma variável, da esquerda para direita, de 1 até N (N = quantidade de dados). No nosso exemplo, nossas linhas geram as seguintes variáveis:

  • $1: um caracter especial gerado pelo w3m que eu decidi ignorar
  • $2: o mês
  • $3: o ano
  • $4: a quantidade de artigos publicados, cercados por parênteses

Nosso programa awk anterior, portanto, deve ser modificado da seguinte forma:

awk '/[0-9][0-9][0-9][0-9] \([0-9]+\)$/ { print $4, $2, $3 }'

Nossa saída, agora, seria:

(1) Junho 2008
(2) Maio 2008
(6) Abril 2008
(5) Março 2008
(16) Fevereiro 2008
(23) Janeiro 2008
(18) Dezembro 2007
(13) Novembro 2007

Ótimo! Agora nossos dados estão quase prontos para serem passados ao sort. O problema são os parênteses cercando a quantidade de artigos. Se passarmos os dados dessa forma para o sort ele não realizará a ordenação corretamente. Precisamos, portanto, realizar uma simples substituição em todas as linhas: eliminar os 2 parênteses. Poderíamos tentar fazer isso diretamente no awk, mas certamente o código-fonte perderia legibilidade, e talvez fosse obrigado a deixar de ser um one liner (e tirar todo o propósito deste artigo!). A saída, portanto, é escolher a melhor ferramenta para o trabalho: sed.

Passo 3: Eliminar caracteres desnecessários

Este simples comando sed irá substituir os parênteses de abertura e fechamento por uma string vazia em todas as linhas do texto que chegar como entrada:

sed 's/[\(|\)]//g'

Nossa entrada, que era assim (apenas as 2 primeiras linhas):

(1) Junho 2008
(2) Maio 2008

Sairá do sed assim:

1 Junho 2008
2 Maio 2008

Com essa saída o sort é capaz de fazer a tarefa dele: ordenar as linhas.

Passo 4: Ordenar as linhas

Por padrão o sort ordena as linhas da mesma forma que um dicionário ordena seus verbetes. Assim, por exemplo, 10 apareceria antes de 9. Para instruir o sort a ordenar as linhas de entrada como se elas fossem dados numéricos, utilizamos a opção -g, e para inverter a ordenação (colocando o maior número no início e o menor no fim), utilizamos a opção -r. Nosso último filtro, portanto, é o seguinte:

sort -gr

E quando aplicado à saída do programa sed:

1 Junho 2008
2 Maio 2008
6 Abril 2008
5 Março 2008
16 Fevereiro 2008
23 Janeiro 2008
18 Dezembro 2007
13 Novembro 2007

Nos devolve:

23 Janeiro 2008
18 Dezembro 2007
16 Fevereiro 2008
13 Novembro 2007
6 Abril 2008
5 Março 2008
2 Maio 2008
1 Junho 2008

Problema resolvido!

Comentários adicionais

É importante ressaltar que se, ao fim do passo 1, a quantidade de artigos publicados no mês estivesse aparecendo na primeira coluna das linhas, não seria necessário utilizar o awk no passo 2, pois para filtrar linhas de um arquivo basta utilizar o programa grep.

Também seria possível, após o passo 4, fazer com que a quantidade de artigos publicados no mês voltasse a ser a terceira coluna de cada linha se adicionássemos mais uma chamada ao awk:

awk '{ print $2, $3, $1 }'

E se quiséssemos restaurar os parênteses, então o programa acima se tornaria:

awk '{ print $2, $3, "("$1")" }'

Agora você já deve entender o que esses dois programas fazem.


Se você tem TV por assinatura vista seu nariz de palhaço

Se você é brasileiro e possui TV por assinatura, vista seu nariz de palhaço!

De acordo com reportagem da Folha:

O TRF (Tribunal Regional Federal) do Distrito Federal liberou a cobrança do ponto extra pelas empresas de TV por assinatura. A liminar foi assinada pelo juiz federal substituto Roberto Luis Luchi Demo, da 14ª vara.

Destaque para esta declaração:

O presidente da ABTA, Alexandre Annemberg, comemorou a decisão e afirmou que “tinha certeza” de que as operadoras conseguiriam liberar a cobrança do ponto extra. “Nós acreditávamos desde o início que iríamos conseguir. Essa cobrança é melhor para o consumidor, pois barateia o ponto principal”, argumentou.

Fiquei bastante intrigado para saber qual o custo que essas empresas tem para manter o ponto adicional uma vez que ele já está instalado (exceto por eventual manutenção por conta de problemas técnicos).

Eu já vesti o meu, e você? Ah, nariz verde e amarelo, por favor.


Promoção BR-Linux e Efetividade pelo software livre

Este post é para chamar atenção para esta promoção muito legal que conheci no BR-Linux. Hoje foi anunciado que já são mais de 400 participantes, e que a doação passará de US$ 500,00. Escolhi doar para a Python Brasil. A Wikipédia receberá metade do valor total da doação, e o projeto mais votado pelos blogueiros receberá a outra metade.

Ajude a sustentar a Wikipédia e outros projetos, sem colocar a mão no bolso, e concorra a um Eee PC!

…e também a pen drives, card drives, camisetas geeks, livros e mais! O BR-Linux e o Efetividade lançaram uma campanha para ajudar a Wikimedia Foundation e outros mantenedores de projetos que usamos no dia-a-dia on-line. Se você puder doar diretamente, ou contribuir de outra forma, são sempre melhores opções. Mas se não puder, veja as regras da promoção e participe - quanto mais divulgação, maior será a doação do BR-Linux e do Efetividade, e você ainda concorre a diversos brindes!


Modificando uma tabela Oracle para conversar com o Rails

Minha saga e dos meus colegas de projeto com o Oracle continua. Estamos tentando configurar um framework web (o Rails) para que ele interfira o mínimo possível na definição original das tabelas do nosso banco de dados. Ela é uma base Oracle com convenções próprias que, idealmente, não deveria ter seu esquema modificado de forma a agradar nenhum framework. Não deveria.

Mas eis que o Rails não suporta tabelas com chaves primárias compostas (e a extensão Composite Primary Keys, que resolveria o problema, atualmente não está funcionando). Para quem não tem muita experiência com banco de dados, vou ilustrar com um exemplo de uma tabela que possui uma chave primária composta de 2 colunas (e não 1, que seria o ideal para se trabalhar com o Rails).

Em uma instituição de ensino, por exemplo, poderíamos ter alunos e cursos (disciplinas) vinculados entre si por meio da seguinte tabela:

create table matricula (
    cd_estudante int REFERENCES estudante (cd_estudante),
    cd_curso int REFERENCES curso (cd_curso),
    nota number,
    CONSTRAINT matricula_pk PRIMARY KEY (cd_estudante, cd_curso)
);

Nossa chave primária é, portanto, composta. Para que o Rails consiga interagir com essa tabela é necessário que ela tenha 1 única chave primária (neste caso, uma chave artificial, que chamarei de cd_artificial). Os campos cd_estudante e cd_curso podem continuar formando uma dupla de campos únicos, com a adição de uma restrição de integridade. Nossa tabela “Rails friendly” deveria ter, portanto, a seguinte definição:

create table matricula (
    cd_artificial int,
    cd_estudante int REFERENCES estudante (cd_estudante),
    cd_curso int REFERENCES curso (cd_curso),
    nota number,
    CONSTRAINT matricula_pk UNIQUE (cd_estudante, cd_curso)
);

O problema do nosso projeto é que algumas das tabelas que precisam sofrer essa metamorfose já possuem milhões de registros (ou seja, definir uma nova tabela, migrar os dados da antiga para a nova e remover a antiga custa muito tempo).

Nossa única regalia é poder parar o sistema para realizar as modificações. O que segue abaixo, portanto, é um passo-a-passo de como transformar aquela primeira definição de matricula na segunda, garantindo que, após o procedimento:

  • Todos os registros tenham um cd_artificial populado corretamente
  • Qualquer código-fonte existente que manipule a tabela continue funcionando, pois não precisará saber da existência de cd_artifical
  • Novos registros possam ser inseridos tanto a partir da aplicação web, quanto a partir do sql*plus, sem que um valor para o campo cd_artificial precise ser definido explicitamente.

Para ilustrar melhor o exemplo, apresento agora a definição de todas as 3 tabelas do sistema fictício, e também os registros inseridos para possibilitar o teste do procedimento.

create table estudante (
    cd_estudante int primary key,
    nm_estudante char(30)
);

create table curso (
    cd_curso int primary key,
    nm_curso char(30)
);

create table matricula (
    cd_estudante int references estudante (cd_estudante),
    cd_curso int references curso (cd_curso),
    nota number,
    constraint matricula_pk primary key (cd_estudante, cd_curso)
);

insert into estudante values (1, 'Caio');

insert into curso values (1, 'AWK');
insert into curso values (2, 'PHP');
insert into curso values (3, 'Python');
insert into curso values (4, 'Ruby');

insert into matricula values (1, 1, 5);
insert into matricula values (1, 2, 9);

Observe as colunas e os registros da tabela matricula, para poder comparar com a versão final:

SQL> select * from matricula;

CD_ESTUDANTE   CD_CURSO       NOTA
------------ ---------- ----------
           1          1          5
           1          2          9

Lembre-se de que os passos a seguir se aplicam somente ao Oracle. Se você estiver utilizando MySQL o procedimento é muito mais simples, e não envolve a criação nem de uma seqüência e nem de um gatilho. Provavelmente no PostgreSQL as coisas devem ser mais simples, mas não tenho o conhecimento necessário para dizer com certeza.

Vamos aos passos.

Passo 1 - Remover a restrição de chave primária de cdestudante,cdcurso

Para que a nova chave primária possa ser definida, a antiga deve ser eliminada.

alter table matricula drop constraint matricula_pk;

Passo 2 - Definir a restrição unique para cdestudante,cdcurso

A nossa antiga chave primária garantia que um mesmo aluno não poderia ser vinculado ao mesmo curso mais de uma vez. Como a chave foi eliminada, essa restrição de integridade não existe mais. Precisamos defini-la novamente.

alter table matricula add constraint matricula_pk unique(cd_estudante,cd_curso);

Passo 3 - Adicionar a coluna cd_artificial na tabela

Agora podemos adicionar a coluna que se tornará nossa nova chave primária.

alter table matricula add cd_artificial numeric(10);

Note que, neste momento, a coluna cd_artificial não possui valores para nenhum dos registros de matricula:

CD_ESTUDANTE   CD_CURSO       NOTA CD_ARTIFICIAL
------------ ---------- ---------- -------------
           1          1          5
           1          2          9

Passo 4 - Popular a coluna cd_artificial

Precisamos, portanto, popular a coluna recém-criada. Neste caso queremos atribuir valores a partir de 1 até o número total de registros da tabela.

update matricula set cd_artificial = rownum;

Veja o resultado:

CD_ESTUDANTE   CD_CURSO       NOTA CD_ARTIFICIAL
------------ ---------- ---------- -------------
           1          1          5             1
           1          2          9             2

Passo 5 - Adicionar a restrição de chave primária à coluna cd_artificial

Agora que a nova coluna já possui dados, ela pode se tornar nossa chave primária.

alter table matricula add constraint matricula_pk primary key (cd_artificial);

Passo 6 - Definir a seqüência que populará o campo cd_artificial

Campos auto incrementais não existem nativamente no Oracle da forma como existem no MySQL. Eles precisam ser definidos com um pouco mais de esforço: deve-se criar uma seqüência e um gatilho.

A seqüência fica responsável por guardar, de forma transacional, um número atual, e gerar um próximo número quando solicitada. Neste caso, como nossa tabela já possui 2 registros, precisamos que a seqüência inicie em 3:

create sequence matricula_seq start with 3;

Passo 7 - Popular o campo cd_artificial automaticamente

O gatilho (trigger) será responsável por interceptar a inserção de um registro na tabela matricula. Todo registro terá seu campo cd_artificial definido como matricula_seq.nextval antes da inserção (before insert), sem que seja preciso defini-lo explicitamente.

create or replace trigger matricula_pk_trig
   before insert
   on matricula
   for each row
begin
   select matricula_seq.nextval
   into :new.cd_artificial
   from dual;
end;
/ -- Esta contra-barra marca o fim da declaração da trigger.

Na verdade, é possível forçar um valor diferente de matricula_seq.nextval para o novo registro, desde que esse novo valor não viole a restrição de integridade da chave primária.

Para testar o gatilho, vamos inserir um novo registro que não especifica cd_artificial:

SQL> insert into matricula (cd_estudante,cd_curso,nota) values (1,3,7);

SQL> select * from matricula;

CD_ESTUDANTE   CD_CURSO       NOTA CD_ARTIFICIAL
------------ ---------- ---------- -------------
           1          1          5             1
           1          2          9             2
           1          3          7             3

Pronto! Agora o Rails será capaz de manipular essa tabela sem problemas.


Sequence CurrVal no Oracle

Estou tentando construir uma aplicação Rails sobre uma base de dados Oracle já construída, com suas próprias convenções de nome, sem chaves artificiais para tabelas que fazem relacionamentos NxM… enfim, estou tendo um certo trabalho. A pior parte, no entanto, é que não sou aquilo que se pode chamar de “expert” em Oracle, muito pelo contrário. E foi aí que começaram meus problemas na tarde de hoje.

Eu estava tentando entender como o Rails gerenciava um campo “auto incremental” no Oracle. Para quem não sabe, esse conceito de “auto incremental” é recorrente no MySQL, onde existe uma instrução específica pra isso. No MySQL, você marca uma chave primária como um campo inteiro, auto incremental, e nunca mais se preocupa. Acontece que no Oracle não é bem assim. Você precisa simular esse comportamento em alguns passos.

O primeiro passo é criar uma tabela que possua como chave primária um campo de tipo inteiro. Por exemplo (todos os comandos SQL do artigo são executados diretamente na péssima interface interativa do Oracle, o sqlplus):

create table students (id int, name char(255));

O segundo passo é criar uma seqüência. O que realmente é uma seqüência não é muito importante neste momento: basta entender que ela guarda um valor corrente, e que é capaz de gerar seu próximo valor. O seguinte comando cria a seqüência que eu utilizei para popular o campo id de todos os registros da tabela student.

create sequence students_seq;

Para inserir um registro em students com o campo id definido por students_seq devemos utilizar a propriedade nextval da seqüência, que retorna o próximo valor da mesma e o define como seu valor atual. Veja o exemplo:

insert into students (id,name) values (students_seq.nextval, 'Caio');
> 1 registro criado.
select id from students;
> 1
select students_seq.currval from dual;
> 1
commit;

Ou seja, tudo funcionando como esperado. Para interagirmos com essa tabela a partir de uma aplicação Rails seria preciso apenas definir a seguinte classe em app/models/student.rb:

class Student < ActiveRecord::Base
end

Podemos agora interagir com nossa base Oracle a partir do console do Rails. Vejamos os seguintes comandos no console:

>> Student.find :all
=> [#<Student id: 1, name: "Caio                                               ...">]
>> joao = Student.new(:name => 'Joao')
=> #<Student id: nil, name: "Joao">
>> joao.save
=> true
>> joao.id
=> 2

Na primeira linha recuperamos todos os registros, e nos é retornado apenas um, que criamos anteriormente diretamente via Oracle. Na terceira linha definimos um novo objeto, e na quinta linha salvamos esse objeto no banco. Nesse momento, a consulta que o Rails executou foi, na prática, a seguinte:

insert into students (id,name) values (students_seq.nextval, 'Joao');

Ou seja, antes da inserção o valor corrente de students_seq avançou 1 unidade, tornando-se 2. Esse valor foi retornado para o comando insert, e Joao ganhou um id igual a 2.

Se agora abrirmos o console do Oracle, você esperaria que o valor corrente de students_seq fosse 2, certo? Mas veja o que o Oracle nos diz:

select students_seq.currval from dual;
> A seqüência students_seq.currval ainda não foi definida nesta sessão

De início não dei muita importância pra essa mensagem, pensei: “mas como, se o Rails atribuiu valor 2 pro último registro, essa consulta TEM que retornar 2!”. Mas a mensagem do Oracle diz tudo o que precisamos saber (embora de uma forma que lembra uma mensagem de erro genérica que você também gera para os seus sistemas quando está com preguiça).

O problema é que o currval de uma seqüência realmente depende da sessão onde estamos. Por sessão, neste caso, entende-se o contexto em que as consultas estão sendo executadas. Se eu abro um console do Oracle (sqlplus) crio uma sessão. Se o fecho e o abro de novo, acabei de gerar uma nova sessão.

Na sessão Oracle mantida pelo console do Rails, esse valor certamente é 2. Mas esse valor não é o mesmo nas outras sessões, acredito eu por conta do controle de concorrência. Pois se, enquanto eu escrevo este artigo, o nextval da seqüência foi solicitado 20 vezes por outras transações, é claro que currval não poderá continuar sendo 2. Além disso, calcular esse valor real não me parece trivial e nem muito útil - talvez por isso o Oracle exiba apenas o valor da sessão.

select students_seq.nextval from dual;
> 3

Como o Oracle me informou “3″, sei que nenhuma outra sessão manipulou essa seqüência nesse meio tempo. Para quem entende de Oracle isso certamente era óbvio, mas pra mim demorou um tempo pra cair a ficha.


Bash One Liners #1

Em: 17/06/2008 Tags: sort, awk, Bash Comentários (1) Referencie do seu blog (Trackback)

Recentemente passei a trabalhar em um projeto que faz muito uso de Bash (ou Shell Script, o termo mais popular no Brasil). Passei, desde então, a prestar mais atenção em construções corriqueiras como um history | grep, descobrindo formas de resolver com diferentes programas baseados em linha de comando tarefas pequenas (ou não) do dia-a-dia. Esses programas (sort, grep, sed, awk, entre outros) tornam-se muito mais úteis, claro, quando podem ser combinados através de um pipeline. Quando conseguimos combinar programas Linux em 1 só comando compacto, acabamos de criar um programa one liner (de uma só linha).

É possível que esses programas funcionem em qualquer shell que você escolher (csh, ksh, entre outros), mas como há algumas diferenças na sintaxe dessas implementações, intitulei a série “Bash One Liners”, pois é apenas no Bash que as soluções serão testadas. Para saber que Shell você utiliza digite, num terminal:

echo $SHELL

Sem muita pretensão, irei publicar aqui no blog soluções one liners que criei (ou copiei) para resolver problemas no trabalho. Todos os artigos terão a mesma estrutura, que basicamente descreve o problema inicial, os programas utilizados na solução, e como a solução pode ser construída através de pipelines. Vamos ao primeiro!

Problema: tenho um arquivo com uma lista de nomes que eu gostaria de ordenar, colocando um asterisco à frente de cada linha, para formar uma “bulleted list”.

Solução inclui: sort e awk.

Exemplo: temos um arquivo types.txt com o seguinte conteúdo:

decimal
integer
float
datetime
date
timestamp
time
text
string
binary
boolean

Nossa transformação é feita em 2 passos. No primeiro ocorre a ordenação:

$ sort types.txt

Que devolve o texto na saída padrão como:

binary
boolean
date
datetime
decimal
float
integer
string
text
time
timestamp

Com um pipe podemos direcionar essa saída para a entrada do Awk, que irá imprimir cada linha precedida por um asterisco e um espaço em branco:

$ sort types.txt | awk '{print "* " $0}'
* binary
* boolean
* date
* datetime
* decimal
* float
* integer
* string
* text
* time
* timestamp

Problema resolvido!


Instalando o plugin Flash no Mandriva 2008 Spring 64 bits

Instalar o suporte a Flash no Firefox 2 do Mandriva 2008 Spring 64 bits não é tarefa intuitiva, mas uma vez que se aprende como fazer são poucos passos.

Importante: tanto o pacote .rpm quanto o pacote .tgz disponíveis para download no site da Adobe não funcionaram com a minha instalação.

O procedimento que funcionou pra mim é o seguinte: visite o site de adição de mídias do Mandriva. Na combo “Version” selecione “2008.1″, e na combo “Architecture” selecione “i586″ (isso mesmo, não selecione “x86_64″). Em seguida clique no botão “Add PLF Medias”. Quando o Firefox perguntar se deseja abrir ou salvar ou arquivo, indique “Abrir com”, e defina como programa o “Add urpmi media” (que é a opção padrão).

O Mandriva fará uma atualização dos repositórios de código-fonte da sua instalação. Ao fim do processo abra um terminal e instale o Flash:

$ su
# urpmi flash-player-plugin

Feche e abra novamente o Firefox. Se tudo correu bem o plugin Flash estará funcionando.