arquivo

Arquivo da tag: script

Dona Fernanda resolveu casar-se com Carlos, o padre porém disse que os noivos não poderiam escolher a data de casamento devido a grande quantidade de solicitações na igreja. Vários noivos também estavam ansiosos para saber quando poderiam se casar naquela linda igreja, para dizer a cada casal o dia exato em que eles poderiam se casar o padre solicitou que eles fornecessem de 1 até 5 dias no mês de sua preferência e desenvolveu um algoritmo que ajudaria a resolver este impasse de forma aleatória e justa agora e no futuro, ele definiu:

  • T – quantidade de casamentos na fila
  • M – mês do casamento
  • N – quantidade de dias do mês disponível
  • Vx – Valor do dia na posição X (V1, V2, V3…)

ENTRADA VÁLIDA

T
N V1 V2 V3 … Vx
M

Cada linha corresponde a uma entrada do casal, então se T for igual 10, existiriam 10 casais para casar na igreja em determinado mês, e por consequência, haveriam 10 linhas de entrada informando os dias preferidos do casal.

POR EXEMPLO

5
5 2 7 5 8 14
5 2 4 14 8 15
1 4
0
3 2 7 9
2

RESTRIÇÕES

T > 0 && T <= 20
M > 0 && M <= 12
N > 0 && N <= 5
V > 0 && V < 32 

  • O dia a ser escolhido deve ser o menor do grupo
  • Caso um casal tenha selecionado um dia já escolhido por outro ele ficará com o próximo dia possível, se houver (por exemplo, A = 4 = { 1, 3, 4, 6 } se os dias 1, 3 e 4 já tiverem sido escolhidos, o casal poderá tentar o próximo item, o quarto número, o dia 6), mas precisa ser sempre o menor número do grupo.
  • Em caso de não haver outro dia disponível para o casal deverá ser escrito:
    • “O casal número N só pode casar no próximo mês pois já tem um casal nos dias selecionados”

  • Em caso de violação de restrição deverá ser escrito
    • “Padre, foi encontrado uma inconsistência nos dados.”

RESPOSTA VÁLIDA / SAÍDA VÁLIDA

Padre, são 5 Casamentos em Fevereiro
O casal número 1 ficou de casar no dia 2 de Fevereiro
O casal número 2 ficou de casar no dia 4 de Fevereiro
O casal número 3 só pode casar no próximo mês pois já tem um casal nos dias selecionados
Padre, foi encontrado uma inconsistência nos dados.
O casal número 5 ficou de casar no dia 7 de Fevereiro

EXPLICAÇÃO DA SAÍDA

“Padre, são 5 casamentos em Fevereiro”
 é o número T de casamentos de entrada e o mês M da entrada

“O casal número 1 ficou de casar no dia 2 de Fevereiro”
é o primeiro casal que tem os dias N = {2, 7, 5, 8, 14} disponíveis e o menor possível é o dia 2 de Fevereiro

“O casal número 2 ficou de casar no dia 4 de Fevereiro”
 é o segundo casal que tem os dias N = {2, 4, 14, 8, 15} disponíveise o menor possível é o dia 4 de Fevereiro

“O casal número 3 só pode casar no próximo mês pois já tem um casal nos dias selecionados”
é o terceiro casal que tem os dias N = {4} disponíveis mas como já existia um casal com o dia 4, não é possível realizar o casamento

“Padre, foi encontrado uma inconsistência nos dados do casal 4.  :(”
é a mensagem de erro em caso de violação de restrição

“O casal número 5 ficou de casar no dia 7 de Fevereiro”
é o quinto casal que tem os dias N = {2 7 9} disponíveis e o menor possível é o dia 7 de Fevereiro

MAIS TESTES PARA VALIDAÇÃO

Gerador de testes aleatórios válidos

bash$ ( T=$(( (RANDOM % 20) + 1 )); echo $T; \
for i in `seq 1 $T`; \
do N=$(( (RANDOM % 5) + 1 )) ; echo -n "$N "; \
for x in `seq 1 $N`; do V=$(( (RANDOM % 31) + 1)); echo -n "$V "; done; \
echo; done; echo $(( (RANDOM % 12) +1 )) )

Teste #01

5
5 21 26 4 1 15 
5 19 11 7 16 17 
1 28 
4 29 6 21 25 
1 11 
5

Teste #02

3
3 28 26 7 
2 29 16 
3 8 14 15 
4

Teste #03

5
3 17 31 16 
1 15 
1 7 
4 31 30 12 1 
2 20 27 
3

Teste #04

18
1 21 
3 23 24 5 
5 15 11 19 28 8 
5 11 9 16 16 5 
1 4 
1 4 
4 4 8 7 26 
4 23 12 11 28 
1 7 
2 28 27 
3 27 13 31 
3 30 29 11 
5 2 5 10 20 14 
5 4 16 5 17 25 
2 3 20 
2 17 2 
5 19 21 2 24 25 
5 16 8 18 23 28 
5

Teste #05

11
5 7 19 30 2 22 
3 8 23 30 
5 25 4 16 17 31 
3 18 31 14 
3 6 3 19 
2 20 1 
2 27 22 
2 16 19 
4 9 28 18 21 
2 10 20 
2 29 9 
7

Quer ver a minha versão com entradas e saídas funcionando??
http://pastebin.com/VvbxBZWD

Conseguiu resolver? Poste suas respostas nos comentários! Quer saber a solução? Entre em contato comigo ou procure na lista de Shell-Script a thread “Desafio Shell-Script #001 do Mulato” 😉

Para quem desenvolve ou acompanha um projeto livre e precisa estar sempre atualizado com os últimos commits segue um script que ajuda bastante no processo, por enquanto só deve funcionar no git e no subversion.

Se você tem uma pasta apenas para os repositórios como eu (/home/mulatinho/repo) basta adicionar o script abaixo e definir as variáveis $subdir (caso tenha subdiretórios com repositórios) e a $nodir (caso não queira incluir arquivos e/ou diretórios na atualização). Segue os exemplos:

$ cat updaterepo.sh
#!/bin/bash
basedir=${HOME}/repo
subdir="github"
nodir="codigolivre.org.br|update.sh"

function do_update()
{
	echo "entrando em '${1}'.."
	cd ${1} 2>/dev/null

	repositorio=`echo ${1} | awk -F'/' '{print $NF}'`
	if git status >/dev/null 2>&1;
	then
		echo "atualizando git repositorio '${repositorio}'"
		git pull
	elif svn status | egrep -i 'not a working copy' >/dev/null 2>&1;
	then
		echo "atualizando svn repositorio '${repositorio}'"
		svn update
	else
		echo "'${repositorio}' nao eh um repositorio git ou svn"
	fi

	echo
	echo
}

#principal
for workdir in ${basedir}/*; 
do
	if echo ${workdir} | egrep "${subdir}" >/dev/null 2>&1
	then
		rdir=${workdir}
		for workdir in ${rdir}/*;
		do
			do_update "${workdir}"
		done
	elif echo ${workdir} | egrep "${nodir}" >/dev/null 2>&1
	then
		continue
	else
		do_update "${workdir}"
	fi

done

cd ${basedir}

Rodando o script e vendo o resultado de todos os repositórios listados em (${HOME}/repo) sendo atualizados!

$ ./update.sh 
entrando em '/home/mulatinho/repo/gcc'..
atualizando git repositorio 'gcc'
remote: Counting objects: 91, done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 42 (delta 34), reused 0 (delta 0)
Unpacking objects: 100% (42/42), done.
From git://gcc.gnu.org/git/gcc
   3cef9c1..23c6c8a  master     -> origin/master
   0afe1df..03e935b  gcc-4_7-branch -> origin/gcc-4_7-branch
   fe4904a..4ef7667  gcc-4_8-branch -> origin/gcc-4_8-branch
   3cef9c1..23c6c8a  trunk      -> origin/trunk
Updating 3cef9c1..23c6c8a
Fast-forward
 gcc/ChangeLog                           |  28 +++++++++++++
 gcc/DATESTAMP                           |   2 +-
 gcc/config/rs6000/linux64.h             |  30 +++++++-------
 gcc/config/rs6000/rs6000.md             |  34 ++++++++++------
 gcc/config/rs6000/sysv4.h               |  49 +++++++++++------------
 gcc/config/sh/iterators.md              |   3 ++
 gcc/config/sh/predicates.md             |  28 +++++++++++++
 gcc/config/sh/sh.c                      |  16 ++++++++
 gcc/config/sh/sh.md                     | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/testsuite/ChangeLog                 |   7 ++++
 gcc/testsuite/gcc.target/sh/pr55303-1.c |  87 ++++++++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/sh/pr55303-2.c |  35 ++++++++++++++++
 gcc/testsuite/gcc.target/sh/pr55303-3.c |  15 +++++++
 13 files changed, 417 insertions(+), 51 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/sh/pr55303-1.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr55303-2.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr55303-3.c
 13 files changed, 417 insertions(+), 51 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/sh/pr55303-1.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr55303-2.c
 create mode 100644 gcc/testsuite/gcc.target/sh/pr55303-3.c

entrando em '/home/mulatinho/repo/geany'..
atualizando git repositorio 'geany'
Already up-to-date.

entrando em '/home/mulatinho/repo/github/bacuri'..
atualizando git repositorio 'bacuri'
Already up-to-date.

entrando em '/home/mulatinho/repo/github/docs'..
atualizando git repositorio 'docs'
Already up-to-date.

entrando em '/home/mulatinho/repo/github/pub'..
atualizando git repositorio 'pub'
Already up-to-date.

entrando em '/home/mulatinho/repo/github/sfm'..
atualizando git repositorio 'sfm'
Already up-to-date.

entrando em '/home/mulatinho/repo/gus-pe'..
atualizando git repositorio 'gus-pe'
Updating '.':
A    teste
A    teste/teste.txt

entrando em '/home/mulatinho/repo/keymouse'..
atualizando git repositorio 'keymouse'
Already up-to-date.

entrando em '/home/mulatinho/repo/linux-stable'..
atualizando git repositorio 'linux-stable'
Already up-to-date.

entrando em '/home/mulatinho/repo/slapt-get'..
updating git repository 'slapt-get'
From http://software.jaos.org/git/slapt-get
   9617037..d1a5737  master     -> origin/master
 * [new branch]      slack13.37 -> origin/slack13.37
Updating 9617037..d1a5737
Fast-forward
 ChangeLog                  |   6 +
 default.slapt-getrc.i386   |  10 +-
 default.slapt-getrc.x86_64 |  10 +-
 example.slapt-getrc        | 116 ++++++++-------
 example.slapt-getrc.i386   | 122 +++++++--------
 example.slapt-getrc.x86_64 | 124 ++++++++--------
 po/bg.po                   |  78 ++--------
 po/cs.po                   |  71 ++-------
 po/{cz.po => da.po}        | 350 +++++++++++++++++++------------------------
 po/de.po                   |  86 ++---------
 po/el.po                   | 105 ++++---------
 po/es.po                   |  96 +++---------
 po/es_AR.po                |  95 +++---------
 po/es_ES.po                | 104 +++----------
 po/fr.po                   | 303 +++++++++++++++----------------------
 po/{en.po => he.po}        | 370 +++++++++++++++++++++-------------------------
 po/hu.po                   |  60 ++++----
 po/id.po                   |  82 ++--------
 po/it.po                   |  78 ++--------
 po/ja.po                   |  84 ++---------
 po/nl.po                   |  76 ++--------
 po/no.po                   |  78 ++--------
 po/pl.po                   |  83 ++---------
 po/pt.po                   | 607 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 po/pt_BR.po                |  95 +++---------
 po/pt_PT.po                |  85 ++---------
 po/ro.po                   |  77 ++--------
 po/ru.po                   |  44 ++----
 po/sk.po                   |  71 ++-------
 po/sl.po                   |  80 ++--------
 po/sv.po                   | 136 ++++++-----------
 po/tr.po                   |  79 ++--------
 po/uk.po                   | 150 ++++++-------------
 po/vi.po                   |  80 ++--------
 po/zh_CN.po                |  66 ++-------
 src/action.c               |   2 +-
 src/main.c                 |   1 +
 37 files changed, 1678 insertions(+), 2482 deletions(-)
 rename po/{cz.po => da.po} (51%)
 rename po/{en.po => he.po} (52%)
 create mode 100644 po/pt.po

entrando em '/home/mulatinho/repo/xf86-video-intel'..
atualizando git repositorio 'xf86-video-intel'
Already up-to-date.

entrando em '/home/mulatinho/repo/xfce4-notes-plugin'..
atualizando git repositorio 'xfce4-notes-plugin'
Already up-to-date.

Okay, mas eu tenho que ficar rodando esse lance toda hora!? Não!

$ crontab -e
0 * * * * /home/mulatinho/repo/updaterepo.sh

Pronto! Agora a toda hora que passa todos os seus repositórios serão atualizados sem bronca! É isso, continue acompanhando!

So here I am again posting about shell script, in these days I was needing store the return code of an script in multiple places and then in the final of this shell show the status of these return codes.

So basically I was needing check every command or sub-script that was running  in the main code, as far we know every time that one command or script are executed the value of ‘$?’ is changed, so if I run an command that return different of zero (fail) and then some thing that return zero (success) and check the return code in the last line I will never know that in the final of script something went wrong.

So I decided to make something to store the value of all commands that are executed with one particularity, when there one error in script I store the error in a place and then I explicity show the error in the final of log. The result of this script follow bellow:

#-- source of retStore.sh --
#!/bin/bash
[ -z $AMBIENTE ] && export AMBIENTE=depwiz
fret=/tmp/depwiz.${AMBIENTE}.ret
so_initcode() {
echo 0 > $fret
}
so_retcode() {
[ -f $fret ] && retcode=$(cat $fret)
[ -z $retcode ] && retcode=0;
return $retcode;
}
so_setcode() {
retnew=$?
[ -f $fret ] && retcode=$(cat $fret)
[ -z $retcode ] && retcode=0 && echo $retnew > $fret
[ $retcode -eq 0 -a $retnew -ne 0 ] && echo $retnew > $fret
echo "{*} retCode: $retnew, statusCode: $(cat $fret)"
}
#-- source of retStore.sh --

Now when I try to execute a large script and need to catch all errors I use something like that (only an simple example of an script):

#-- source of simpleScript.sh --
source retStore.sh
so_initcode
ls 2>/dev/null 1>/dev/null          # success here.
so_setcode
ls /root/* 2>/dev/null 1>/dev/null  # error here.
so_setcode
uxhfuihuf                           # error here.
so_setcode
ls 2>/dev/null 1>/dev/null          # success here.
so_setcode
so_retcode
echo ret is: $?
#-- source of simpleScript.sh --

This gave me an output like that:

[mulatinho@work:~] ./simpleScript.sh
{*} retCode: 0, statusCode: 0
{*} retCode: 2, statusCode: 2
./simpleScript.sh: line 30: uxhfuihuf: command not found
{*} retCode: 127, statusCode: 2
{*} retCode: 0, statusCode: 2
ret is: 2

Now everything is cool and the errors are caught  ! 😀

Texto de 2006, adicionado ao blog.

Há muito tempo eu escrevi uma introdução ao bash script e olhando ontem, resolvi fazer uma adaptação aqui no blog e colocar pra o pessoal ler, quem sabe alguém que esteja iniciando no mundo unix se interesse 🙂 Este texto contém uma visão introdutória sobre o que é uma shell e como a manipular, mas especificamente a Bourne-Again SHell (BASH).

ÍNDICE

1. – A SHELL NO LINUX
1.1 – O que é uma shell?
1.2 – Principais tarefas da shell.

2. – O BÁSICO DO BÁSICO.
2.1 – Conectivos padrões e retornos lógicos.
2.2 – A matemática na shell.
2.3 – Tipos de parametros.

3. – VARIÁVEIS
3.1 – Variáveis ambiente.
3.2 – Atribuindo comandos à variáveis.

4. – ESTRUTURAS DE LOOP E CONDIÇÕES
4.1 – Usando loops.
4.2 – Fazendo condições.

5. – AVANÇANDO
5.1 – Redirecionando entrada/saída de dados.
5.2 – Usando comandos em background e adcionando interrupções.
5.3 – Alguns comandos: sed, cut, wc, od.
5.4 – Cores no terminal.

6. – ARQUIVOS DE CONFIGURAÇÃO
6.1 – .bashrc
6.2 – .bash_history

BIBLIOGRAFIA:
Programação Shell Linux, Júlio Cezar Neves, Brasport.
The GNU Bash Reference Manual
http://www.network-theory.co.uk/bash/manual/toc/

1. A shell no Linux

A shell está no Linux desde o início e serve justamente para executar os comandos com mais eficiência do que seriam executados se estivessem sem a organização que ela oferece. O Linux desde o início foi desenvolvido em partes que formam um todo utilizando um núcleo que chamamos de KERNEL, essas partes são pequenos ou grandes programas que utilizam chamadas do kernel para realizar a maioria de suas tarefas em conjunto ou separados.

Digamos que se quisessemos copiar um arquivo para outro usariamos algo como o comando cp ou se quisessemos apenas modificar seu nome usariamos o comando mv. Para que tudo fosse mais prático os seus desenvolvedores pensaram em algo que pudesse interpretar e unir com mais facilidade esses comandos/programas, foi aí que originou-se a shell com o intuito de organizar estes comandos, interpretando-os e também com uma poderosa linguagem de programação com o conjunto de seus programas. O sistema operacional UNIX e seus derivados como no nosso caso, o Linux, é composto por várias “camadas”. A mais interna de todas elas é a que chamamos de KERNEL ou núcleo, ele é responsável por interagir diretamente com o HARDWARE simplesmente fornecendo o controle total para que o resto do sistema funcione, por exemplo quando escrevemos algo em um arquivo ou mesmo quando estamos lendo, o KERNEL envia sinais para que o processador procure na trilha e no setor certo do disco onde está sendo gravado/lido certo dado que foi processado.

Os programas por sua vez quando são executados as vezes precisam que o usuário forneça dados como argumentos ou opções, no nosso terminal então precisamos de algo que entenda o que está sendo pedido e é finalmente aí onde entramos com a SHELL.

1.1 O Que é uma shell?

Pra começo de conversa, no momento em que você se loga no sistema você já está numa SHELL. A SHELL é um meio pelo qual o usuário entra com dados para o sistema fazendo com que o sistema identifique esses dados e os converta para o sistema operacional poder lê-los sem ter que resolvê-los, diminuindo assim o tempo que seria gasto se a SHELL não interpretasse esses dados e o deixasse para que o kernel também fosse resolvê-lo. Tendo em vista esses dados podemos dizer que a SHELL é uma ferramenta poderosa que usamos para interpretar nossos comandos antes de roda-los fazendo com que seja possível o uso de parametros, substituição de strings, modificação de variáveis ambiente, etc. Também vale ressaltar que a shell vem com uma linguagem poderosa, chamada shell script, que nos permite utilizar laços de condição e processamento de certos dados, principalmente os de entrada e saída.

1.2 Principais tarefas da Shell.

As principais tarefas da nossa shell são compreender e organizar a linha de comando que o usuário envia na entrada de dados, fazendo assim com que
os comandos executados rodem com mais performance e de um jeito muito mais estruturado, depois de feito isso a shell ordena de ESPAÇO em ESPAÇO cada comando e argumento enviado, procurando-os na variável $PATH que contém os caminhos onde o usuário em questão pode executar programas. A shell também é capaz de agir como um interpretador de linguagem estruturada, permitindo-nos fazer scripts com a mistura de comandos que o sistema nos fornece. Podemos resumir então estes processos desta forma:

  1. A shell pega os dados e os interpreta antes de serem executados.
  2. Usa variáveis ambiente como o $PATH, que nos mostra os diretórios aos quais o usuário tem acesso para execução de comandos.
  3. Processa como os dados vão sair e entrar corretamente (input/output).
  4. A nível de programação ela executa laços, condições, etc.

2. O básico do básico.

Este capítulo é chamado de básico do básico porque relaciona coisas bem iniciantes a nível de noções da shell no Linux, para obtermos uma visão
correta é preciso ter noção de como funciona alguns comandos do linux que estão diretamente ligados ao uso da nossa shell, por exemplo para listarmos
o conteúdo de um diretório não precisamos entrar nele para ver seus arquivos, basta que usemos o comando de listagem com o diretório como
parametro, por exemplo:

$ ls /home/alexandre/txtz/y0/
bash.txt  plantz.txt  provas.txt  userfile.txt

ou

$ cd /home/alexandre/txtz/y0
$ pwd
/home/alexandre/txtz/y0
$ ls
bash.txt  plantz.txt  provas.txt  userfile.txt

Como podemos ver isso tudo é muito básico mas é necessário ter uma idéia que estamos trabalhando com um interpretador de comandos que nos oferece além de qualidade para entender o que está sendo digitado também praticidade e velocidade. Vejamos como seria se eu quisesse me movimentar um diretório abaixo:

$ cd ..
$ pwd
/home/alexandre/txtz
$ ls -lh
-rw-r--r--    1 alexandr users        307k Dec 22  2003 focalinux.txt
drwxr-xr-x    2 alexandr users         200 Sep  3 12:01 y0

Vemos que descemos um diretório abaixo de onde estávamos usando o comando cd seguido de 2 pontos finais, a shell interpreta isso fazendo com que nós voltemos um diretório do orignal a qual estávamos. Uma observação interessante a se comentar é que o diretório y0 nada mais é do que um
arquivo assim como todos os diretórios do linux, a diferença é a flagzinha ‘d’ na sua permissão.

Outra coisa que devemos observar é que como na matemática a shell da preferência a opções que estejam entre parenteses, por exemplo:

$ ls txtz/y0/
bash.txt  file.txt  plantz.txt  provas.txt  userfile.txt
$ pwd
/home/alexandre
$ ( cd txtz/y0/ ; cat file.txt )
voce esta me lendo! ohh :~
$ pwd
/home/alexandre

Ué ? por que eu não fui pro diretorio txtz/y0/ ? e como eu li o arquivo file.txt se ele estava dentro desse diretório e eu ainda continuo no $HOME
CALMA! Não foi nenhuma macumba.. o que aconteceu foi que a shell deu preferência ao comando entre parenteses, executou o comando em uma shell filho e retornou a shell normal matando a shell filho. Outro tipo de forma pra mostramos como o parenteses está em preferência com a shell é usando um comando qualquer entre parenteses:

$ echo "A versão do meu kernel é: $(uname -r)"
A versão do meu kernel é: 2.4.26

Para saber como funciona essa interpretação de comandos nós temos que
voltar a coisas bem iniciais por isso chamamos essa parte de básico do
básico, imaginemos então:

$ ls
eu.txt voce.txt nos.txt vos.txt eles.txt

Temos um comando simples ‘ls’ que quando executado na shell
retorna os arquivos do diretorio em que estamos. Agora vejamos:

$ ls e*
eu.txt eles.txt

Digitamos novamente o ‘ls’ sendo que com um argumento, a primeira letra
‘e’ seguida de um ASTERISCO, a shell então retorna todos os arquivos do
diretório que contém a primeira letra que indicamos mais TODO O RESTO, que
é o que significa o asterisco. Vemos agora a utilidade das aspas no echo:

$ echo 1 2 3...    VOCE  EH ESTA  APRENDENDO  BASH
1 2 3... VOCE EH ESTA APRENDENDO BASH
$ echo "1 2 3...    VOCE  EH ESTA  APRENDENDO  BASH"
1 2 3...    VOCE  EH ESTA  APRENDENDO  BASH

OBS: Veja que a mudança ocorre na saída do texto quando usamos às aspas.

Resumindo, ela interpretou o comando antes de executa-lo, isso se faz
muito útil para que você as vezes não tenha que fazer vários comandos com
um objetivo só ou as vezes queira obter mais performance. Por exemplo no
caso de interagir com um ou mais comandos, deve-se usar conectivos.

2.1 Conectivos padrões e retornos lógicos.

TABELA DE CONECTIVOS                       TABELA VERDADE
+-----------+---------------------------------+   +---+---+------+
| CONECTIVO | DESCRIÇÃO                       |   | A | B |A && B|
+-----------+---------------------------------+   +---+---+------+
|     &&    | AND (E) lógico.                 |   | 0 | 0 |  0   |
|     ||    | DOUBLE PIPE (OU) lógico.        |   | 0 | 1 |  0   |
|     |     | PIPE (OU) lógico.               |   | 1 | 0 |  0   |
+-----------+---------------------------------+   | 1 | 1 |  1   |
$ df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/hda1             9.8G  2.9G  6.9G  29% /
/dev/hda4              14G  3.2G   10G  23% /mnt
$ echo $?
0

O duplo caracter $? (dólar,interrogação) retorna o valor do resultado do
comando digitado na entrada, fornecendo 0 se o comando retornar OK e 1 se
ele retornar com algum erro (observemos que é o inverso da tabela verdade
usada na lei de Boole). Com isso podemos usar os conectivos e colocar dois
comandos numa linha apenas, por exemplo:

$ cd /
$ echo "Arquivos do diretório atual ($PWD):" && ls
Arquivos do diretório atual (/):
bin  boot  dev  etc  home  lib  mnt  opt  proc  root  sbin  tmp  usr  var

*OBS: Como o resultado do comando echo e do ls são 0 (e na tabela verdade
da shell o 0 representa LIGADO), indicando que eles retornaram VERDADEIRO
os dois comandos são colocados na tela. O $PWD é uma variável do sistema
que será explicada depois 😉

Então já podemos dizer que a tabela VERDADE da nossa shell ficaria da
forma inversa da tabela original da lei de Boole.

TABELA VERDADE DE EXECUÇÃO NA SHELL

+---+---+------+
| A | B | A&&B |          RETORNO:
+---+---+------+          --------
| 0 | 0 |  0   |          0 = OK.
| 0 | 1 |  1   |          1 = ERRO.
| 1 | 0 |  1   |
| 1 | 1 |  1   |
+---+---+------+

Ou seja, os dois comandos só seriam impressos na tela juntos se ambos os
termos fossem 0 quanto ao seu resultado. Agora vejamos se no primeiro
argumento o resultado fosse maior que ou igual a 1, e o próximo fosse 0
usando o AND condicional ficaria:

$ ls /root && echo "Fim do /root"
ls: /root: Permission denied
$ echo $?
1

*OBS: O 1° argumento retorna um numero diferente de 0 fazendo com que o
2° comando nao seja executado porque de acordo com a tabela verdade
do AND condicional o 2° comando só executado se houvesse uma verdade
lógica ou um retorno 0;.

Temos:

$ ls /root
ls: /root: Permission denied
$ echo $?
1

$ echo "Fim do /root"
Fim do /root
$ echo $?
0

Então:

!(1 && 0) =>; 1 (ERRO/DESLIGADO)

Já no caso do PIPE (|), a prioridade dos argumentos sempre estão do lado
direito(ou 2° argumento) é muito útil quando estamos lendo algo no console
quando o texto é muito grande e precisamos realizar pausas pra leitura:

$ cat /usr/doc/Linux-HOWTOs/Bash-Prompt-HOWTO | grep PS1

O comando cat é executado fazendo com que todo o arquivo seja impresso na tela embora com uma diferença, todo o texto é enviado para o comando grep, que por sua vez procura por strings no arquivo e entrada retornando apenas as linhas que contenham o argumento passado no comando ‘grep’ ;]

2.2 A matemática da shell.

Temos várias formas para realizarmos calculos matemáticos na shell,
podemos simplesmente usar o comando ‘expr’ ou usar cálculos entre
parenteses com as definições de operadores da shell.

TABELA DE OPERADORES
+-------+-----------------------------------------------+
| VALOR | SIGNIFICADO                                   |
+-------+-----------------------------------------------+
|   +   | Como na matemática, serve para somar números. |
|   -   | Também como na matemática, subtrair.          |
|   /   | Este é o operador para divisão de números.    |
|   *   | Operador de multiplicação.                    |
|   %   | Resto de uma divisão.                         |
| == != | Igual e diferente.                            |
| <= >= | Menor igual que, maior igual que.             |
+-------+-----------------------------------------------+

Podemos realizar operações usando o comando expr mais os números e que
tipo de operadores queremos para realizar cálculos, ou simplesmente usar o
echo $((CALCULO MATEMATICO)), onde dentro desses DOIS parenteses, faremos
o cálculo para ser armazenado ou impresso na tela. Exemplos:

Fazer a soma de 4 + 5:

$ expr 4 + 5
9

A média aritmética de 20+15+10:

$ echo $(( (20+15+10) / 3 ))
15

Multiplicar 3 por 5:

$ expr 3 * 5
expr: syntax error

Ué!? O que houve de errado? bom, relembrando o início a shell interpreta os comandos antes de executa-los, ela entendeu o ASTERISCO como usamos anteriormente significando QUALQUER COISA, só que isso numa operação matemática não faz sentido. O que fazer então? temos que proteger o asterisco da shell pra dar prioridade ao operador e não a interpretação
que a shell faz do asterisco normal.

Novamente, protegendo o asterisco, multiplicando 3 por 5:

$ expr 3 * 5
15

Há também outra forma de fazermos cálculos, usando a cálculadora padrão do GNU a bc. Como vimos, usando o PIPE odemos jogar uma informação no 2° argumento de um comando:

$ echo "(4 * 27) + 21" | bc
129

Usamos às aspas para proteger o parenteses da shell e jogamos a operação
na calculadora bc que nos retorna o resultado rapidamente.

2.3 Tipos de parâmetros.

O uso de parametros é quase constante em uma linha de comando de uma
pessoa que esteja acostumada à shell, eles tornam tudo mais fácil e as
vezes se fazem extremamente necessários.

o> parametro de substituição de comando

para a shell saber onde executar os comandos é necessário uma forma de
procura por programas para executar no sistema, a variável $PATH indica
onde o usuário em questão verá os diretorios separados por ‘:’ do
sistema aos quais ele obterá acesso à comandos.

podemos utilizar um parametro para executar comandos na shell fazendo
com que seu output saia na tela ou seja armazenado em alguma variável,
a shell bash vai entender o que estiver entre os parenteses como um
comando de algum diretório do $PATH.

SINTAXE

$(COMANDO) => Abre uma subshell e executa o comando retornando a
shell pai e saindo da subshell.

ou

`comando` => Executa um comando normal do sistema.

$ echo -e "todays fortune:n $(fortune)"
todays fortune:
"All flesh is grass"
-- Isiah
Smoke a friend today.

$ SYSTEM=`uname -s`
$ echo "Sistema: $SYSTEM"
Sistema: Linux

voce pediu pra a shell imprimir uma frase, seguida de um comando
‘fortune’ que faz parte de um pacote chamado bsdgames, ele é bem
interessante, é composto de milhares de frases e pensamentos de
filósofos, autores de livros, etc. já no segundo exemplo usamos uma
variável SYSTEM para armazenar o retorno do comando ‘uname -s’ depois
imprimimos na tela.

o> parametros com chaves

as vezes queremos nos referir a um nome de arquivo em vários tipos de
extensão, ou fazer coisas do tipo, para isso podemos ao inves de ter
que escrever toda a linha de comando repetidamente usamos as chaves.

$ echo m{a,e,o}ngo          ou         $ ls *.{bz2,txt}
mango mengo mongo                      IAO-paper.txt focalinux.txt
gcc-3.3.tar.bz2 retlib.txt

evitamos ter que fazer repetições na linha de comando colocando as
sequencias necessarias entre chaves.

o> outros parametros

podemos trocar strings de um parametro, declaramos ele desta forma:
${PARAMETRO/STRING/NEWSTRING} , onde STRING é a ocorrência que você
deseja modificar e o NEWSTRING é a nova string que vai ficar.

$ STR="estou aprendendo a errar"
$ echo ${STR/errar/viver}
estou aprendendo a viver

ou se quisessemos ver o tamanho de caracteres de uma string, fariamos
assim ${#STRING}, onde STRING seria a variavel ou palavra/frase.

$ echo $STR
estou aprendendo a errar
$ echo ${#STR}
24

para pegarmos um argumento da linha de comando usamos o carácter
dólar seguido da ordem do seu argumento, exemplo:

$ ./comando arg1 arg2 arg3
$1 -> arg1
$2 -> arg2
$3 -> arg2

3. Variáveis.

Uma coisa muito útil na shell é a possibilidade de armazenamento de
dados na memória, fazendo isso podemos atribuir à variaveis saídas de
comandos, calculos aritméticos e strings. Para setar uma variável na
shell basta fazer:

$ A=1
$ B=HELLO
$ C="HELLO WORLD"

$ echo $A $B $C
1 HELLO HELLO WORLD

Veja que dessa vez não usamos o DÓLAR para setar a variável A,B,C esse
dólar só vai ser colocado quando quisermos que a shell retorne o valor
da variável. Para remover a variável do sistema é só fazer:

$ unset C
$ echo $C

3.1 Variáveis ambiente.

Há uma série de variáveis padrões definidas pela SHELL quando você se
loga nela, estas servem para organizar de forma mais eficiente tudo que
o usuário tem acesso, pode fazer e quer saber. Vamos ver algumas delas:

$HOME => Indica o diretório raiz do usuário que esta logado na shell.
$PATH => Diretórios aos quais o usuário tem acesso à comandos.
$PWD => Diretório onde o usuário se encontra.
$USER => Usuário logado na shell.

Para vermos todas elas usamos o comando ‘export’ que serve também para
setar as variáveis ambiente na shell. Para ver todas:

$ export
…………………….

Para setar:

$ export VAR="Conteúdo"
$ echo $VAR
Conteúdo

3.2 Atribuindo comandos à variáveis.

Podemos utilizar as variáveis também para armazenar saída de comandos
do sistema, para isso colocamos o comando entre crases, vejamos exemplos:

$ cd txtz/y0/
$ pwd
/home/alexandre/txtz/y0
$ var=`ls`
$ echo $var
bash.txt file.txt plantz.txt provas.txt slides.txt userfile.txt

Entramos no diretório e setamos uma variável ‘var’ com o valor da saída
do comano ‘ls’, depois imprimimos o valor com o comando echo.

$ proc=`cat /proc/cpuinfo | grep "model name" | cut -d" " -f4-10`
$ echo "PROCESSADOR: $proc"
PROCESSADOR: Athlon(tm) XP 1700+

4. Estrutura de loops e condições.

Podemos elaborar processos repetidas vezes de acordo com a condição que
desejarmos, usando as estruturas de loop e condições começamos a falar de
shell script que nada mais é do que uma forma estruturada de organizar os
comandos do sistema utilizando tudo que aprendemos em conjunto(variáveis,
comandos, retornos de comandos, etc).
Há diferença entre eles é que os loops executam uma certa sequencia de
comandos digitados pelo programador até que aconteça algo que será
processado e de acordo com o tipo de loop, terminado ou continuado,
enquanto as condições esperam que o programa receba algo e de acordo com
um teste que foi previsto pelo programador anteriormente execute um bloco
de códigos ou não.
Para setar um arquivo como shell script deve-se coloca-lo com uma
permissão de execução, fazendo:

$ chmod +x arquivo
$ ./arquivo

Tendo em vista isto, temos também que entender que no shell script os
operadores para condições matemáticas tambem mudam, exemplo:

| OPERADOR | SIGNIFICADO                                 |
+----------+---------------------------------------------+
|   -lt    | less than (menor que).                      |
|   -le    | less or equal than (menor ou igual que).    |
|   -gt    | greater than (maior que).                   |
|   -ge    | greater or equal than (maior ou igual que). |
|   -eq    | equal than (igual que).                     |
|   -ne    | not equal (diferente de).                   |
+----------+---------------------------------------------+

Também é bom lembrar que num arquivo shell script, a primeira linha
deverá sempre ser a declaração da shell em que estamos programando:

#!/bin/bash

4.1 Usando loops.

Os loops servem entre outras coisas para executar um bloco de códigos
até que um teste seja atingido, vejamos alguns tipos de loop:

o> until

SINTAXE

until [ 'TESTE' ] ; do
CÓDIGO....
done

O comando until serve para executar um laço até o seu TESTE retorne
um valor diferente diferente de 0 (ou seja, até que o teste seja falso)

#!/bin/bash
IN=10

until [ $IN -lt 4 ] ; do
echo "LOOP: $IN"
IN=`expr $IN - 2`
done

$ ./until
LOOP REVERSO: 10
LOOP REVERSO: 8
LOOP REVERSO: 6
LOOP REVERSO: 4

o> while

SINTAXE

while [ 'TESTE' ] ; do
CÓDIGO...
done

Fazendo o inverso do until, o comando while executa o CÓDIGO até que
o retorno de seu TESTE seja igual a 0 (ou seja verdadeiro), exemplo:

#!/bin/bash
IN=0

while [ $IN -lt 4 ] ; do
echo "LOOP: $IN"
IN=`expr $IN + 1`
done

$ ./while
LOOP: 0
LOOP: 1
LOOP: 2
LOOP: 3

o> for

SINTAXE

for (( expr1 ; expr2; expr3 )) ; do
CÓDIGO...
done

Onde temos o primeiro modo de utilizar o for na shell, o expr1 é um valor que será atribuido à uma variável, o expr2 é um teste que será feito até que seu resultado seja verdadeiro, fazendo com que o bloco de código seja executado repitidamente e expr3 será o que será feito quando o teste for verdadeiro, poucos usam o for desta forma embora na minha opnião seja mais eficiente. Por exemplo:

#!/bin/bash
for (( i=0 ; i<5 ; i++ )); do
echo "loop: $i"
done

$ ./for
loop: 0
loop: 1
loop: 2
loop: 3
loop: 4

4.2 Fazendo condições.

É necessário fazer condições quando recebemos algo da entrada de um
usuário e queremos realizar um TESTE com esses dados para ver qual rumo
o programa deve tomar. Vamos usar dois tipos de comandos básicos para
execução de condições, são eles:

o> if-then-else

SINTAXE

if [ 'TESTE' ] ; then
CÓDIGO...
fi

Executa o TESTE, se ele for verdadeiro executa o bloco de CÓDIGO senão sai sem executar nada dentro do if.

if [ 'TESTE' ] ; then
CÓDIGO...
elif [ 'TESTEDOIS' ] ; then
CÓDIGO DOIS...
fi

Executa o TESTE, aciona o bloco de CÓDIGO se o resultado do teste for verdadeiro.. depois executa o TESTEDOIS e se for verdadeiro ele executa o bloco de CÓDIGO DOIS.

if [ 'TESTE' ] ; then
CÓDIGO...
else
CÓDIGO DOIS...
then

Aqui ele executa o TESTE, entra no bloco de CÓDIGO se o resultado
do teste for verdadeiro, senão ele entre no bloco de CÓDIGO DOIS.

#!/bin/bash
IN=$1

if [ "$1" == "Mulher" ] ; then
echo "Olá senhorita :)~"
elif [ "$1" == "Homem" ] ; then
echo "Como vai meu bom homem?"
else
echo "Escolha sua opção sexual rapaz!"
fi

$ ./ifthenelse
Escolha sua opção sexual rapaz!
$ ./ifthenelse Homem
Como vai meu bom homem?
$ ./ifthenelse Mulher
Ola senhorita :)~

o> case

SINTAXE

case ARG in
PS1)
CÓDIGO
;;

PS2)
CÓDIGO DOIS
;;
esac

Aqui o teste ocorre em cima de ARG, o case explode várias possíveis alternativas que podem ser PS1, PS2, PS3, …, PSN. Uma boa função do case é poder fazer essas possibilidades usando meta-caracteres.

#!/bin/bash
IN=$1

case $IN in
[a-c])
echo "Tu és homem!"
;;
[d-f])
echo "Tu és mulher!"
;;
[0-9])
echo "Tá confuso?"
;;
esac

$ ./case b
Tu és homem!
$ ./case 3
Tá confuso?

5. Avançando.

Nesta parte vamos começar a complicar mais um pouquinho pra descomplicar bem muito, hã? é isso mesmo, aqui vamos mostrar alguns comandos que a maioria nem chega perto mas que são úteis demais para um shell scripter.

5.1 Redirecionando entrada/saída de dados.

Podemos direcionar como os dados irão entrar e como irão sair em nossa shell usando operadores, para começarmos a fazer isso devemos lembrar os 3 tipos padrões de entrada/saída de dados, são eles:

(0 ou STDIN) => Standard Input (Entrada Padrão).
(1 ou STDOUT) => Standard Output (Saída Padrão).
(2 ou STDERR) => Standard Error (Saída de erro padrão).

Tendo em mente isso, usamos operadores para o redirecionamento que são parecidos com os símbolos da matemática:

| OP | SIGNIFICADO |
+—-+—————————————————————-+
| N> | Onde N, é o valor da saída de dados (1 ou 2), fazendo com que |
| | o redirecionamento da saída seja feito há direita do operador. |
| > | Envia os dados para arquivo, criando-o caso não existe ou |
| | apagando seu conteúdo anterior e adcionando novo, caso exista. |
| >> | Aqui há o redirecionamento de dados para o FINAL do arquivo |
| | caso exista, ou uma criação de arquivo, caso não exista. |
| < | Setamos na shell que a entrada padrão não irá vir do teclado |
| | e sim do arquivo em questão. |
| << | Indicamos um LABEL para o começo de uma linha fazendo com que |
| | a linha só termine quando houver a proxima ocorrência do LABEL |
+—-+—————————————————————-+

$ echo "Ohh! voce me leu :~" > file.txt
$ cat file.txt
Ohh! voce me leu :~

$ echo "Que trágico!" >> file.txt
$ cat file.txt
Ohh! voce me leu :~
Que trágico!

$ tr e i < file.txt
Ohh! voci mi liu :~
Qui trágico!

$ mount /dev/cdrom /mnt/cdrom 2> error.txt
$ cat error.txt
mount: only root can do that

5.2 Usando comandos em background e adcionando interrupções

Podemos rodar comandos em modo background., que significaria mais ou
menos que executamos um comando deixando-o numa file de espera, então
ele em alguns programas que precisam de entrada de dados só irá
executar suas funções quando agente o chamar no sistema.

$ vim file.txt &
[1] 22956
Î   Î
`---|-------- 1 = First Job (Primeiro trabalho.)
'--- 22956 = PID (Process ID).

Vêmos que ele carregou o programa numa subshell, mas não executou a sua função que era de editar o arquivo, para fazermos isso, digitamos

$ fg 1

E então o ID do processo em background sairá da subshell e virá para nossa shell principal, podemos fazer isso várias vezes. Outra coisa muito útil é que podemos adcionar interrupções ou simplesmente modifica-las de acordo com o nosso interesse, para agente começar a mecher nos sinais devemos é claro, entendê-los:

0 => Saída normal do programa.
1 => Sinal de quando se recebe um kill -HUP
2 => Interrupção forçada pelo teclado CTRL+C.
15 => Sinal de interrupção de programa quando se é kilado. (kill PID).

Isso é muito útil quando fazemos um programa e queremos ter certeza
que o usuário não fará a besteira de termina-lo usando CTRL+C ou se
fizer nós termos como ajeitar sua trapalhada, por exemplo:

$ trap “echo THE POWER OF TRAP” 2

5.3 Alguns comandos: sed, cut, wc, od.

Aqui vamos ver alguns comandos que são muito úteis quando se esta
trabalhando com arquivos, é importante domina-los para uma maior
velocidade e eficiência.

o> sed

SINTAXE

sed <OPCAO> <EXPRESSÃO> <ARQUIVO>

EXPRESSÂO

SUBSTITUIÇÃO

sed ‘s/FRASE/NOVA/’ <ARQUIVO>

Usando sed podemos substituir FRASE(strings, números, frases)
por uma NOVA palavra ou frase, vejamos um exemplo simples:

$ cat file.txt
batatinha quando nasce, esparrama pelo chão.
$ sed 's/esparrama/cai/' file.txt
batatinha quando nasce, cai pelo chão.

EXPRESSÃO

EXCLUIR

sed ‘X,Yd’ <ARQUIVO>

Não imprime linhas de X à Y.

sed ‘/PALAVRA/d’ <ARQUIVO>

Não imprime linhas que contém PALAVRA.

$ cat file.txt
Linux comanda o mundo.
Windows comanda o mundo.
Freebsd comanda o mundo.

$ sed ‘2,3d’ file.txt
Linux comanda o mundo.

$ sed ‘/Windows/d’ file.txt
Linux comanda o mundo.
Freebsd comanda o mundo.

EXPRESSÃO

NEGAR

sed -n …. <ARQUIVO>

$ sed -n '/Windows/!p'
Linux comanda o mundo.
Freebsd comanda o mundo.

o> cut

Serve para separar de acordo com o seu DELIMITADOR as palavras e
imprimir apenas o que é pedido.

SINTAXE

cut <OPTION> <ARQUIVO>

OPÇÕES

-d => Usado para definir qual vai ser o delimitador.
-fN => De acordo com o delimitador, a Nª palavra.

$ cat /etc/passwd | cut -d":" -f1
root
bin
daemon
adm
lp
sync
.......

o> wc

Este comando serve para imprimir a quantidade de bytes, palavras
e linhas de um arquivo, é geralmente usado depois de um PIPE.

SINTAXE

wc <OPCOES> <ARQUIVO>

OPÇÕES

-l => quantidade de linhas
-w => quantidade de palavras
-c => quantidade de bytes (caracteres).

$ wc -l file.txt
2 file.txt
$ wc -c file.txt
34 file.txt

o> od

O comando od serve para imprimir um arquivo de acordo com uma
especificação dada pelo usuário, podemos imprimir um arquivo texto
com suas letras em formato hexadecimal, octal, etc.

SINTAXE

od <OPCOES> <ARQUIVO>

OPÇÕES

-h => imprime letras e números em hexadecimal.
-o => imprime letras e números em octal.

$ od -h file.txt
0000000 684f 2168 7620 636f 2065 656d 6c20 7565
0000020 3a20 0a7e 7551 2065 7274 67e1 6369 5c6f
0000040 0a21
0000042

5.4 Cores no terminal.

Podemos sim adcionar cores para dar ênfase a alguma frase ou enfeitar nossos programas shell, usamos então uma definição especial para isso, um caracter ESC seguido de uma [ mais códigos de cores e terminando por uma barra invertida seguida de um m, ‘]m’, vejamos a lista de códigos para suas cores:

| TEXTO | FUNDO | COR               |   | CÓDIGO | SIGNIFICADO   |
+-------+-------+-------------------+   +--------+---------------+
|   30  |   40  | Preto (cinza).    |   |   0    | Desliga tudo. |
|   31  |   41  | Vermelho.         |   |   1    | Negrito.      |
|   32  |   42  | Verde.            |   |   5    | Pisca pisca.  |
|   33  |   43  | Marrom (amarelo). |   |   7    | Reverso.      |
|   34  |   44  | Azul.             |   +--------+---------------+
|   35  |   45  | Roxo.             |
|   36  |   46  | Ciano.            |   *OBS: ESC == 33 (Octal)
|   37  |   47  | Cinza (branco).   |
+-------+-------+-------------------+

$ echo -e “33[40;31;1mSPORT RECIFE33[m”
$ echo -e “33[42;32;1mLOL33[m”

6. Arquivos de configuração.

Estes arquivos servem para quando iniciarmos a shell, carregarmos ou
executarmos váriaveis/programas, mudarmos o prompt, adcionarmos aliases
e várias outras opções.

o> .bashrc / .bash_profile

Este arquivo é executado assim que logamos na shell, podemos então
utiliza-lo para setar o prompt, adcionar aliases padrões, etc.

o> .bash_history

Este é o arquivo onde ficama a história dos processados pela shell
no sistema, ele fica no diretório $HOME do usuário.

%d blogueiros gostam disto: