Peczenyj's Blog

Just Another /Perl|Ruby|C++|Java|Python|JavaScript|Flash|Bash/ Hacker

Resolvendo Problemas Comuns 7 - Open Failed: |

Imagine um arquivo com algumas linhas duplicadas:
$ cat arquivo
permission denied
bad interpreter
missing separator
set correct localle
parameter list too long
unary operator expected
parameter list too long
bad interpreter


Obter as linhas distintas pode ser feito com a ajuda do sort + uniq

$ cat arquivo | sort | uniq
bad interpreter
missing separator
parameter list too long
permission denied
set correct localle
unary operator expected


- Puxa! Que ótima combinação! Vamos guarda-la?

Bom, podemos querer guardar este e outros comandos em uma variável de ambiente também, afinal, deve funcionar sem maiores problemas, certo?
$ CMD="sort | uniq"
$ cat arquivo | $CMD
sort: open failed: |: No such file or directory


- OPA! Eu sabia, maldito shell, encrenca com tudo!

Tsc… isso acontece porque o pipe | não foi informado como um ‘pipe’ e sim como a string “|” – e o sort não conseguiu abrir o arquivo “|”.
Este tipo de problema pode ser resolvido pelo eval – ele interpreta novamente as strings na linha de comando.
$ eval "cat arquivo | $CMD"
bad interpreter
missing separator
parameter list too long
permission denied
set correct localle
unary operator expected


- Ah, agora funciona. Mas esse eval ai ficou feio…

Então vamos criar um alias para o comando!
$ alias cmd="sort | uniq"
$ cat arquivo | cmd
bad interpreter
missing separator
parameter list too long
permission denied
set correct localle
unary operator expected


Perceba que o comportamento do alias é diferente de uma variavel de ambiente. Devemos ficar atento à correta interpretação da nossa linha de comando pelo shell corrente, senão vamos ter resultados nem sempre amigáveis.

Ah, sim, o cat nesse exemplo é completamente supérfluo, poderia ser assim: ‘sort arquivo | uniq’

- E o uniq precisa do sort ?

Sim… sem o sort ele fatalmente vai se perder, e é muito mais facil eliminar linhas repetidas que estejam em sequencia do que aleatórias. É bom dar uma lida no man destes comandos pois possuem opções muito poderosas!

Comments

Tiago Peczenyj
Claro, sort + uniq é um prato cheio!

Uma coisa interessante é nessa dupla é, por exemplo, imprimir apenas as linhas repetidas ou não repetidas de um texto (opções -u ou -d) e, quando a entrada vem ordenada, o resultado é extremamente confiável.

Entretanto não lembro se não existe algum furo no sort -u apenas, vou pesquisar.

Abração!
Alexsander
Olá! muito boas as dicas q tens disponibilizado!
só uma sugestão:
“sort -u” também remove duplicidades.
abraços
t+

Resolvendo Problemas Comuns 6 - Unary Operator Expected

Uma desatenção, muito comum quando trabalhamos com variáveis de ambiente no shell é que, quando elas não foram setadas ainda, o shell expande elas para… nada.

$  [ $XALALA == "oi" ] && echo 'ok' || echo 'nok'
-bash: [: ==: unary operator expected
nok


Nesse caso o (resultado do) teste da variável até pode fazer sentido, porém troque o == por um != e veja o resultado. A solução é proteger a variável com aspas!

$  [ "$XALALA" != "oi" ] && echo 'ok' || echo 'nok'
ok


Simples e rápido!

Comments

Tiago Peczenyj
Bah, não tinha reparado nisso.

E faz sentido, afinal [[ é built-in e [ é, geralmente, um apelido para o comando /bin/test

valeu!
Cláudio
Outra solução: usar [[ ]] ao invés de [ ].

Resolvendo Problemas Comuns 5 - the Parameter List Is Too Long

Essa é raro, mas acontece

$ cd /meu/diretorio
$ rm *.dll
Error: The parameter list is too long


- O que? Eu não posso apagar todos os meus 3459834574935734957 arquivos?

Bom, primeiro vamos analisar o que aconteceu: a linha de comando ‘rm *.dll’ é expandida pelo shell corrente a ‘rm arquivo1.dll arquivo2.dll … arquivoN.dll’ e, nesse caso, esta lista de parâmetros foi demais pro probrezinho do rm.

Com o xargs é facil de resolver!
$ find /meu/diretorio -name '*.dll' -print | xargs rm


O que ele faz? o xargs recebe pela stdin toda uma lista de parâmetros que será entregue ao programa rm. Se esta lista extender o limite do sistema, então o xargs, inteligentemente, irá executar o rm uma vez, com a lista que for possível e, depois, executar de novo, até que todos os parâmetros sejam lidos. Aliás o xargs possui muitas opções interessantes, vale a pena dar uma estudada nele.

E assim todas as dll’s são apagadas – em definitivo, pois com rm ‘tr00’ não tem undelete ;-)

Comments

Tiago Peczenyj
Ah sim, quem limita/expande os coringas é o shell. Acho que escrevi uma frase ambígua – valeu!
eljunior
na verdade a lista de parâmetros não foi demais para o `rm’, quem limita isso é o próprio shell (tanto é que, num caso desses, nem um ls * funciona…). também não funcionaria somente `xargs rm’, se fosse limitação do `rm’; seria necessário limitar a quantidade de parâmetros com a opção -n pro `xargs’. ;-)

nas máquinas que usei, o limite do bash geralmente fora 32768 parâmetros…

falou!

Resolvendo Problemas Comuns 4 - Corrigindo O Localle

Precisamos estar atento que as variáveis de ambiente de localização podem atrapalhar, e muito, o comportamento de algumas expressões regulares.

Por exemplo, se eu quero encontrar uma palavra que começe com a e termine com o (ex: ação)
$ cat arquivo
luz, camera, ação
$ grep -oE 'a\w+o' arquivo # nao mostra nada!

Antes de sair dizendo que o linux, grep ou as expressões regulares não prestam, vamos testar o mesmo comando no nosso ‘idioma’
$ LC_ALL=pt_BR grep -oE 'a\w+o' arquivo
ação

Ahá! Agora vamos ver um exemplo mais interessante:
$ tr '[:lower:]' '[:upper:]' < arquivo
LUZ, CAMERA, AçãO
$ LC_ALL=pt_BR tr '[:lower:]' '[:upper:]' < arquivo
LUZ, CAMERA, AÇÃO

Perceberam como a variavel altera o comportamento das ERs?

Como ultima dica: sempre que precisarem comparar textos independente da ‘caixa’ (se maiúscula ou minúscula), usem os recursos de ignorecase da ferramenta utilizada. Converter um texto todo para minúscula pode não apenas ser afetado pela localização como existem idiomas onde alguns caracteres não tem o exato correspondente entre uma caixa e outra como nós pensamos – é o caso do idioma Turco, onde o ‘i’ maiúsculo não é ‘I’. E, principalmente, não tente fazer isso.

Mais informações em ‘man locale’ ;-)