Introdução
Básico de código.
Last updated
Básico de código.
Last updated
O que é um shell?
Tipos de shell, arquivos de configuração de shell(do sistema e do usuário) - OK
Declaração de variaveis e Variaveis de ambiente(env/set/unset/export/alias)
Como executar scripts
descritores padrão(0,1,2)
Comentários, Input, Output e processamento básico, fluxo linear.
Escapando linhas longas \
Condicionais( if case )
Loops(until,while e for) c0d1ngbyt3sfromnone
Funções
Recebendo valores na execução do script.
Carregando outros scripts ( source . )
Processamento de dados.
O que é um Shell?
Shell, do inglês significa concha e a razão disso é porquê faz a interface entre o usuário e o sistema operacional, ficando no meio dos dois, como se o Kernel estivesse dentro da concha, observe a imagem abaixo:
Créditos ao responsável.</center>
Algo engraçado de pensar é que no Ghost in The Shell o shell é aonde o "Ghost" fica, que no caso é o cérebro transplantado, meio que o shell é o que permite a interação com o mundo como um todo, é totalmente épico.
A interface shell funciona como o intermediário entre o sistema operacional e o usuário graças à CLI(command line interface) que é seu novo melhor amigo a partir de agora, você pode não levar a sério mas você vai começar a notar que o shell pode fazer tudo pra você e quanto mais tempo você passar fora dele mais você perde. A função do shell basicamente é ler a linha de comando, interpretar seu significado, executar e devolver o resultado pelas saídas.
Existem vários tipos de shell o que no universo *nix não é novidade, você tem algo livre onde cada um faz a mesma coisa de formas diferentes, isso em alguns casos até chega a ser um problema devido a padronização, contudo existem vários tipos de shell e segue abaixo alguns deles:
zsh (Zero Shell)
Tem umas dessa lista ai que eu nunca ouvi falar e tem vários outros shells que não listei, sinta-se a vontade para clicar nos links. O shell padrão da maioria das distribuições linux é o bash e é o que eu mais uso pois não tenho muito saco pra ficar experimentando outras coisas e é o que vamos usar durante todo esse paper.
Cada usuário no linux quando loga recebe um shell que fica configurado no arquivo /etc/passwd, na verdade nem todos os usuários do sistema recebem um shell por questões de segurança e por lógica não faria sentido atribuir um shell à um usuário do sistema. Quando eu falo usuário do sistema eu me refiro à usuários que o sistema cria para isolar processos, não são usuários para seres humanos. Segue um exemplo do arquivo /etc/passwd
A ideia não é explicar a estrutura do arquivo e não o farei, mas você pode ter uma explicação [aqui](https://pt.wikipedia.org/wiki/Passwd_(arquivo)). O que eu quero te mostrar está na ultima coluna delimitada por ':' que é referente à shell do usuário, repare que temos /bin/bash onde /bin é o diretório de binários e shell é o programa que está dentro daquele diretório que é o nosso shell. Repare que tem usuários com /bin/false como o usuário proftpd por exemplo, isso é uma medida de segurança e lógica pois é um usuário do sistema para gerenciar os processos do serviço do daemon(O 'D' no final é referente à daemon, então sempre que você ver algo que termina com 'd' é provável que seja um daemon do sistema.
Como tudo no linux, você pode configurar o shell do seu usário no sistema ou configurar o default do shell no sistema inteiro. Para realizar as configurações no shell do seu usuário você precisa configurar o arquivo /home/seuusuario/.bashrc e para configurar o shell default de todos os usuário você pode fazer em /etc/bash.bashrc.
Existem dois tipos default de interação no prompt, PS1 e PS2. Suas definições seguem abaixo:
PS1
Basicamente a PS1 é a padrão, é a que nós temos quando entramos na shell, segue:
É uma variável de ambiente configurada no arquivo do usuário que já foi mencionado anteriormente, fica em ~/.bashrc. Abaixo segue o print da variável $PS1;
PS2
A PS2 é quando vamos digitar um comando e quebramos a linha com o caracter '\' no final seguido de enter ou quando o comando não termina na linha por que faltou fechar alguma coisa tipo aspas, então caimos na PS2, segue abaixo:
Print da variável de ambiente PS2
Outra coisa interessante de se configurar é o $PATH. O $PATH é uma váriável de ambiente assim como PS1 e PS2, porém ela é utilizada para indicar aonde estão os binários do sistema para o usuário. Elas podem ser configuradas em um contexto geral no arquivo /etc/profile ou individualmente no diretório home do usuário ~/.profile.
O PATH é importante pelo fato de que, caso você tenha instalado um binário/programa e ele não fique dentro do diretório padrão, você não vai conseguir invocar esse binário na cli simplesmente pelo nome dele, igual acontece com o comando cat por exemplo.
O comando acima indica que o binário cat está no diretório /bin. Para verificar que o diretório /bin está no nosso $PATH, você pode executar o seguinte:
Conforme o output acima, o diretório se encontra no $PATH, logo pode ser invocado pelo nome, sem necessariamente ter que executar o caminho absoluto inteiro. Então você ao invês de fazer isso:
Você faz simplesmente isso:
Para você adicionar algo no $PATH, existem duas formas. A primeira você só precisa redefinir a váriavel e passar o novo local direto na linha de comando, e a outra forma seria alterar o arquivo de configuração citado anteriormente, porém nessa segunda forma, você precisaria relogar no sistema para que as configurações passem a valer.
Primeira forma:
Segunda forma:
E adicione o novo path:
E então você vai precisar relogar no sistema, pode fazer isso simplesmente executando:
Aproveitando que falei sobre caminho absoluto. Existem dois tipos de caminho:
Absoluto -> É o caminho completo desde o diretório raiz até o arquivo, lembrando que o diretório raiz é /
Relativo -> É o caminho relativo ao diretório atual.
Alguns exemplos para te ajudar a entender do que se trata:
Vamos supor que você está no diretorio /etc/ para os dois exemplos a seguir. No primeiro exemplo você vai acessar o arquivo de configuração do apache2 pelo caminho relativo:
Agora você vai acessar pelo caminho absoluto:
Variáveis são lugares na memória que armazenam coisas, podendo ser sobreescritas se você quiser, mudando o valor que ela contém. Para declarar variáveis no shell é simples:
VARIAVEL seria o nome da variavel em si, o simbolo de igualdade = significa atribuição, então você está atribuindo VALOR à VARIÀVEIL. Por convenção e padrão, dizem que é melhor declarar todas as variáveis em caixa alta, ou seja maiusculo. Outro ponto curioso que difrente de outras linguagens, no shellscript você não precisa declarar o tipo da variável, o shell entende tudo como string na verdade, mesmo que seja um número, ele vai tratar como string.
Algumas boas práticas em relação à variáveis:
Prefira maiúsculas para variáveis globais e minúsculas para variávesi locais e temporárias.
Todas variáveis são globais, a não ser quando precedidas pelo comando local.
Não são tipadas.
Podem ser acessadas da seguinte forma ${nome}
Para acessar a variável que você criou é simples também, basta invocar o comando echo e o nome da variável da seguinte forma:
Mais um detalhe, o shellscript identifica váriaveis pelo prefixo cifrão $, caso você esqueça, o shell dará um erro dizendo que não encontrou o comando VARIAVEL. Mas não com o echo, pois o echo vai mostrar o que você jogar pra ele. Mas agora vamos ver outro exemplo onde eu possa te mostrar esse erro acontecendo.
Vamos definir uma variável e atribuir à ela a localização de um arquivo e depois invocar o cat passando a variável:
Agora caso a gente esqueça de usar o prefixo cifrão na variável, o shell irá retornar um erro:
ENV
Agora entrando no assunto de enviroment, nós temos várias variáveis definidas no seu ambiente que indicam várias coisas, vocẽ pode visualizar tais variaveis utilizando o comando env:
Outro comando que pode ser adotado é o printenv, a diferença entre os dois comandos é que o printenv pode requisitar os valores de uma opção especifica:
Vocẽ pode estar utilizando o comando env para definir variaveis de ambiente apenas para executar alguns comandos especificos da seguinte forma:
SET/UNSET
O comando set pode ser empregado para os mesmos propositos que os anteriores, se você executar set sem argumentos, ele irá exibir a lista de variaveis de ambiente, variaveis de shell, variaveis local e funções do shelll. É uma lista bem grande então é recomendado utilizar com o comando less
Nós podemos limpar a saída especificando que o set opere no modo POSIX, modo qual não irá exibir funções do shell. Nós podemos executar isso em um sub-shell evitando que altere variaveis do nosso environment atual:
O Comando acima vai listar todas as variaveis de ambiente e do shell que foram definidas.
Common Environmental and Shell Variables
Here are some common environmental variables that you will come across:
SHELL: This describes the shell that will be interpreting any commands you type in. In most cases, this will be bash by default, but other values can be set if you prefer other options.
TERM: This specifies the type of terminal to emulate when running the shell. Different hardware terminals can be emulated for different operating requirements. You usually won't need to worry about this though.
USER: The current logged in user.
PWD: The current working directory.
OLDPWD: The previous working directory. This is kept by the shell in order to switch back to your previous directory by running cd -.
LS_COLORS: This defines color codes that are used to optionally add colored output to the ls command. This is used to distinguish different file types and provide more info to the user at a glance.
MAIL: The path to the current user's mailbox.
PATH: A list of directories that the system will check when looking for commands. When a user types in a command, the system will check directories in this order for the executable.
LANG: The current language and localization settings, including character encoding.
HOME: The current user's home directory.
_: The most recent previously executed command.
An addition to these environmental variables, some shell variables that you'll often see are:
UNSET
O comando unset pode ser utilizado para remover variaveis e atribudos de variaveis do shell e funções. Por exemplo:
Export
O Comando export pode ser utilizado para exportar variáveis deixando elas disponíveis em todas as threads filhas criadas a partir da sua, o que isso quer dizer, quando vocẽ está numa sessão no shell e vocẽ define uma variável, ela fica restrita apenas áquele environment local, então um exemplo é um script que chama outro scrit. Vamos colocar contexto. Você tem um script que define variaveis e depois chama outro script para executar determinada ação, então vou mostrar um exemplo sem usar export e um utilizando export.
So how do that? Easy ! Script que define a variável e chama outro script para exibir a variavel:
Script que irá exibir a variável:
Executando o script:
Repare que nenhum "CONTENT" foi exibido.
Agora vamos utilizar export:
Outra forma de utilizar o export é a seguinte:
Então nossa variável fica acessivel em outros processos filhos, facilitando muito o trabalho, vamos supor que você crie uma ferramenta que utilize vários scripts, com o export as váriaveis ficariam disponíveis para todos eles.
Outro exemplo utilizando uma sessão no bash, vamos declarar uma variavel e depois abrir um outro bash dentro do bash e tentar acessar aquela variável.
O comando Alias pode ser utilizado para você criar alias mesmo, você pode por exemplo definir um alias que é um comando bem grande e depois apenas invocar com esse 'apelido' do comando.
Se você executar o comando alias apenas ele irá exibir todos os alias definidos:
Vou te mostrar como:
Parece meio inutil mas não é, você pode por exemplo colocar as definições no arquivo ~/.bashrc e então toda vez que o seu usuário logar ele irá carregar esses alias e você poderá executar comandos complexos apenas utilizando o seu respectivo alias, por exemplo, eu criei três alias definidos no arquivo ~/.bashrc:
Então toda vez que eu precisar abrir a IDE pycharm, eu simplesmente digito no shell 'pycharm' e ela é carregada.
Outra coisa interessante sobre os alias é que, se você analisar o arquivo ~/.bashrc vai identificar que existem vários alias ali, por exemplo, pelo menos no meu linux mint:
Isso são alguns atalhos que já vem criados para facilitar sua vida, você poderia por exemplo criar um alias pro comando rm para que ele fique interativo ao invés de já sair apagando, assim você diminui a probabilidade de erro, mas é bem chato ter que ficar confirmando 'Y' para executar o comando porém pode salvar sua vida qualquer dia.
Então vamos lá, vou criar um arquivo chamado delete_me e irei remover ele logo em seguida com nenhum alias do rm criado:
Agora vamos definir o alias:
Ai se for de seu interesse você pode carregar isso tanto no seu ~/.bashrc ou no /etc/bash.bashrc sendo o segundo arquivo o respnosável pela configuração global, ou seja, todos os usuários iriam carregar esse arquivo e pegar variaveis de ambiente e outras configurações de sessão/shell etc.
Como Executar Scripts
Bom, nesse ponto nós já executamos alguns scripts, mas irei estar explicando como é o processo de forma detalhada.
Scripts de shellscript tem seu sufixo como .sh, então sempre que criar um script utilize isso no final do nome.
Vamos lembrar então das permissões, é algo que a gente chama de UGO, que é um acronimo para User, Group and Others. Todo arquivo tem as propriedades do UGO, as permissões de usuário que tal arquivo pertence, do grupo que o arquivo pertence e permissões para outros.
A nomemclatura é bem simples, você pode utilizar o comando ls -l para verificar as permissões em arquivos, se liga só:
O que importa aqui é esse pedaço de output aqui:
O primeiro hífen(-) indica qual o tipo de arquivo, existem vários outros tipos e foge do escopo eu explicar isso agora, mais a frente irei entrar no assunto, contudo o que importa é que quando esse primeiro '-' está apenas como hífen mesmo, significa que é um arquivo normal, regular file. Então nós temos outros 3 blocos com 3 hífens cada. Cada bloco é referente ao UGO, respectivamente, o primeiro bloco ao USER, o segundo ao GROUP e o terceiro á OTHERS.
Existem apenas 3 tipos de permissões, Read(r), Write(w) e Execute(x), logo, no primeiro bloco nós temos rw-, isso significa que só tem permissão de leitura e escrita, no segundo bloco temos rw que também significa leitura e escrita e no ultimo bloco referente ao OTHERS, apenas leitura. Ou seja, não existe nenhuma permissão para execução por parte de nenhuma das três propriedades do UGO.
Se nós tentarmos executar o script, ele irá dar erro:
O ./ indica que o arquivo está no diretório local é uma referencia relativa, poderia ser utilizado o caminho absoluto também da seguinte forma:
Existe uma forma para conseguir executar arquivos sem necessariamente ter permissão de execução, que seria invocando o interpretador, que no nosso caso é o /bin/bash, mas poderia ser o /bin/sh, ou qualquer outro shell que fosse compativel com o script.
Então segue uma forma de se executar tal script sem permissão de execução explicita:
Existem diversos tipos para se definir permissão para um script, contudo irei abordar o mais simples e apenas referente à permissão de execução, o comando que é responsável para alterar as permissões é o chmod:
A sintaxe é simples, eu utilizei u+x para adicionar permissão de execução apenas ao usuário owner do arquivo. Dẽ uma olhada no manual do chmod para aprender sobre outras formas, existe também a equivalencia em octal, mas não irei entrar nesse assunto.
Uma vez com a permissão definida, você pode verificar as permissões do arquivo novamente:
Se reparar agora, no primeiro bloco existe um x, que é referente à permissão de execução, então é possível executar o script:
Descritores padrão.
Bom, falando um pouco sobre descritores de arquivos. Descritore de arquivos são um indicador abstrato que vai fazer o handler sobre como arquivos são acessados ou como entradas e saídas padrão. Não irei entrar a fundo mas irei te dar uma ideia do que estou falando.
0 -> Entrada padrão(STDIN)
1 -> Saída Padrão(STDOUT)
2 -> Saída de erro(STDERR)
Tendo conhecimento disso é possível então redirecionar esses fluxos a seu favor. Um exemplo é a saída padrão, a saída padrão é sempre na console, você pode por exemplo ao invés de exibir na console você poderia encaminhar pra um arquivo, segue exemplo:
Você faz referência ao número do descritor e encaminha pra algum lugar, no caso ali a referencia foi para o 1> que é o STDOUT. Uma observação é como os redirecionamentos são feitos, você pode observar que é usado o > , ele vai encaminhar para um arquivo sobreescrevendo, então se nós executarmos novamente o mesmo comando só irá existir uma linha no arquivo. Se for empregado >> ele irá fazer uma adição no final do arquivo, observe:
Vamos dar uma olhada no STDERR agora, vamos forçar um erro no shell: Com o STDERR normal o erro é exibido na console:
Um truque é redicionar para o buraco negro do linux conhecido como /dev/null, analogicamente é uma lixeira que não tem possibilidade alguma de restore.
Redirecionando para um arquivo:
Um outro truque é utilizar o &> que irá encaminhar tanto STDOUT quanto STRERR para o mesmo local. No exemplo abaixo eu irei utilizar o comando cat para exibir o conteúdo de dois arquivos, o primeiro existe e o segundo não:
Agora redirecionando com o &> eu encamido o STDOUT e o STRERR para um arquivo por exemplo:
Existe também o comando tee que trabalha com esse esquema de redirecionamento porém ele exibe na tela ao mesmo tempo que redireciona para algum lugar, vale a pena dar uma olhada no manual desse cara.
Agora falando sobre pipes, pipes são aquelas barras '|' e utilizando pipes voCê pode exemplo redirecionar o STDOUT de um comando para o STDIN de outro comando:
No exemplo acima é redirecionado o STDOUT do cat para wc -l que irá contar as linhas do arquivo.
Algo que é bastante utilizado é pegar um arquivo de log e usar o grep para filtrar determinadas expressões:
Iremos ir mais a fundo sobre esse assunto mais além.
- Input, Output e processamento básico, fluxo linear.
Ta na hora de colocar a mão na massa!
A primeira coisa na hora de se criar um script é definir o shebang, esse cara é responsável por indicar aonde está o interpretador que irá interpetar o script, nós vamos estar utilizando o bash e ele está localizado no /bin/bash, então nosso shebang fica assim:
Sim, esse #! é o que indica o shebang e o que vem depois é o path pro intereptador.
Um comentário no código é uma linha que o interpretador ignora, você pode usar isso para escrever comentários no código que expliquem o que está ocorrendo, facilitando o entedimento do código ou até mesmo para comentar linhas de código enquanto realiza algum debug, para definir um comentário, apenas adicione #, sim, hashtag, tralha, jogo da velha, qual nome você preferir.
Então vamos começar com o básico, sempre falo que um programa é divido em três partes, entrada, processamento e saída, vocẽ tem a entrada de dados, processa e depois retorna o resultado. Vamos começar de trás pra frente, começar em como ter output de dados do programa:
Para exibir conteúdo na tela é utilizado o comando echo.
Aqui tem um programa bobo que mostra Hello Friend de trẽs formas diferentes:
Antes de executar não esqueça de dar permissão.
Executando o código:
Ele exibiu os três 'echo's na tela, a diferença entre as três formas é a seguinte:
Executando:
Quando se utiliza aspas simples, toda instrução dentro não é executada, ele entende como apenas texto. Quando se utiliza aspas duplas, ele tenta interpretar nomes de variáveis. Assim como sem aspas.
Operadores Matematicos: Exitem duas formas de se realizar calculos, tem até uma terceira mas é gambiarra mas vou estar falando, talvez seja util para você algum dia.
A primeira é utilizando $(( DO THE MATH HERE)), esse é o meu favorito porquẽ considero mais intuitivo, segue exemplo:
Uma segunda forma é utilizar o expr :
Repare que na multiplicação foi necessário escapar com uma contra barra para que o * não fosse interpretado de outra forma.
Um detalhe que não comentei é que para executar o resultado de uma outra instrução como nos exemplos anteriores em uma variável, é necessário chamar um subshell que irá executar aquilo e então será atribuido à variável:
Então aqui nosso código segue um fluxo linear de acordo com as instruções do seu script até chegar ao final.
Como receber valores de entrada de forma interativa? Simples, usamos o read para tal.
Uma coisa importante é um leve detalhe, se você não passar aonde o read vai armazenar o valor, ele armazena numa variavel default chamda REPLY
Para se ter um fluxograma no programa com tomada de decisões é empregado as condicionais, no shellsript nos temos duas funções que processam condições:
if
case
IF
O IF pode ser utilizado para verificar se uma ou mais condições são verdadeiras, se forem verdadeiras, um bloco de código é executado, se não, outro bloco é executado, assim nós temos desvio de fluxo dentro do programa o que é bem interessante.
Então vamos começar do básico: Primeiro vamos definir o que é o test command.
0 -> true
1 -> False
Agora vamos falar sobre o que isso tem a ver com o IF.
Você pode notar que o test é basicamente a verificação de uma condição, muita gente usa o IF e não sabe o que é o test, mas são duas coisas semelhantes porém diferentes. O IF vai verificar se aquele test retorna true, se sim, ele executa um bloco, se não ele faz outra coisa, podendo ser uma nova verificação.
A sintaxe do if é bem simples, você define o IF e então quais os tests que você irá realizar, então coloca o que será executado, existe duas formas básicas de se utilizar:
E a outra forma é colocando o then na linha de baixo, que seria o correto, no exemplo anterior foi usado o ';' para separar um do outro, mas isso é o que vocẽ preferir, não é que é errado usar o exemplo anterior, você pode usar o que te agradar mais.
Assim como a maioria das outras linguagens nós temos também o else que indica, se o bloco do if não for executado porquê ele considerou a condição como FALSE ele irá executar outra coisa, segue exemplo:
Então com base nisso nós já podemos por exemplo fazer uma calculadora com os conhecimentos adquiridos até aqui, eu não passei lógica de programação mas espero que você já saiba, se você já sabe, pare de ler até a proxima linha, caso não saiba, pode continuar e tenten entender o código.
Para realizar as operações de test nas condicionais, é necessário que você adote alguns verificações entre as variaveis, segue abaixo uma tabela com os mais usados:
Comparando Strings
-z -> Verdadeiro se a string estiver vazia.
-n -> Verdadeiro se a string não estiver varia, operação default.
= -> Verdadeoro se as Strings forem iguais.
!= -> Verdadeiro se as Strings forem diferentes.
No shellscript, toda variável é tratada como string, então é bom você verificar colocando aspas duplas para indicar que o parâmetro a ser comparado seja uma string.
Aritmeticos:
-eq -> Verdadeiro se os valores forem iguais.
-ne -> Verdadeiro se os valores forem diferentes.
-le -> Verdadeiro se o primeiro parametro for menor ou igual ao segundo
-ge -> Verdadeiro se o primeiro parametro for maior ou igual ao segundo
-lt -> Verdadeiro se o primeiro parametro for menor que o segundo.
-gt -> Verdadeiro se o primeiro parametro for maior que o segundo.
Make Your Own Code: Escreve um script que receba dois numeros e um operador matemático básico e então identifique qual operação será executada e processe a operação e depois exiba o resultado.
Solução:
Existe uma forma melhor do que ir criando vários IF's sequenciais, um dos motivos para se evitar isso é que você não precisa por exemplo verificar todos as condicionais se você já encontrou qual a operação, então isso meio que gasta mais processamento atoa, para ter um melhor controle disso você pode adotar uma cadeia de condições, quando uma é alcançada as que ainda não foram verificadas são desconsideradas. Muita gente usa isso colocando um IF dentro de um IF, porém o shellscript possui o elif, o elif basicamente diz que, se o if deu False então faça uma nova verificação, definida naquele elif. Um exemplo de sintaxe segue:
Isso pode ter ficado confuso mas você irá entender com o código abaixo:
Uma outra coisa interessante que eu considero gambiarra é, no exemplo que não foi adotado o elif, você poderia ter utilizado o exit para encerrar o programa em cada condição, logo, a condição que fosse válida iria ter seu bloco de código executado e o fluxo do programa encerrava naquele bloco e as condicionais restantes não iriam ser verificadas:
Então dessa forma você iria verificar apenas até a condição que fosse verdadeira e as demais não seriam executadas.
Note que caso você queria executar algum outro código depois do bloco inteiro do IF e ele tiver entrado em alguma condicional, ele jamais chegará ao fim do programa devido ao exit. Nesses casos é melhor você utilizar o elif ou o case e esse problema de tentar sair dentro de uma condição não irá ocorrer pois isso já é tratado pela natureza das funções.
Bom, nós temos também os operadores lógicos, segue abaixo:
&& -> operador lógico AND.
|| -> operador lógico OR.
! -> Operador lógico XOR, negação.
Os operadores lógicos são muito utilizados em condicionais para verificar uma ou mais condições. Vamos à sintaxe:
Bom, vamos colocar a mão na massa, segue um exercicio de fixação: Escreva um programa que recebe o nome e idade do usuário e então verifique se o nome foi inserido e se ele é maior de 18, caso for, exiba que ele pode servidr o exericto, se ele não for, verifique se o nome é válido e se a é suficiente.
O Comando wc será o responsável por verificar quantos caracteres existem no conteudo da variável $NAME.
Uma outra forma de utilizar o if é a seguinte:
Outra forma de redirecionar fluxo do programa é atráves do comando switch. Esse comando é bastante utilizado Menus interativos ou onde se existe diversa possibilidaedes, ele verifica a segunda opção independente do resultado da primeiram então é importante adotar os exit**
Exemplo de sintaxe:
Repare que o case fecha o bloco com um esac e toda verificação termina o bloco com ;;.
Então vamos ao handsON. Escreva um programa que receba dois valores e solicite o tipo de operação básica matematica e então utilizando o case processe a operação e exiba o resultado.
LOOPS, for, while e until.
Vamos falar de laços ou loops, pode chamar de como quiser, ambos são válidos mas eu prefiro chamar de loop. Loops são blocos de códigos que são executados várias vezes até uma condição se torne verdadeira ou deixe de ser verdadeira. No shellscript nós temos três tipos de loop:
for -> Executa uma determinado número de vezes.
while -> Executa até que determinada condição deixe de ser verdadeira.
until -> Executa até que determinada condição se torne falsa.
Então vamos começar com o loop do tipo for A Sintaxe do comando é bem simples, segue:
A variável aux irá receber cada interação do que quer que seja o SOMETHING e pode ter o nome que você quiser. Repare que aqui nós temos a delimitação do bloco utilizando do e done
Segue um exemplo de loop do for percorrendo um valor número de 0 até 10 e exibe os números pares:
No exemplo anterior é utilizado a operação % que é responsável por calcular o resto da divisão.
Você poderia por exemplo utilizar o controle com base em arquivos, segue exemplo:
O exemplo acima irá ler todas as linhas do path que irá fazer referência à um arquivo e então irá contar quantos caracteres tem cada linha. Esse tal arquivo poderia ser o /etc/passwd, uma lista de bruteforce ou qualquer outra coisa que se possa ler e tenha linhas.
Mais um exemplo utilizando o loop For para identificar as portas autorizadas por uma lista de portas que podem estar em listen. As portas que não estiverem no arquivo não estão autorizada.
Então nós estamos usando o comando netstat para exibir as portas ativas e passando para a STDIN do comando awk, usando o cut para delimitar por ':' e pegar o segundo campo e então com o tail</strong> nós pegamos todo a saída formatada removendo apenas as 3 primeiras linhas. Esse comando irá gerar uma lista das portas que estão em listen para que nosso for possa percorrer.
Uma vez dentro do loop For nós temos uma bloco de condição IF, onde é utilizado o grep para procurar dentro do arquivo que o usuário vai definir e pegar o resultado da execução do comando anterior que irá indicar se ele encontrou ou não aquela porta na lista. Se o resultado do comando der 1, significa que a posta não está autorizada.
Para você entender melhor:
Lista com as portas autorizadas:
Verificando o resultado da execução do comamdo grep
Todas as saídas que retornarem 1 é porquê não existem no arquivo, as que retornarem 0 existem. Uma observação é que quando o comando grep executa com sucesso e localiza a string que vocẽ está buscando ele exibe na tela a string. Para contornar isso nós redirecionamos o STDOUT e o STDERR para /dev/null do comando grep assim só o resultado da execução será exibido com o comando $?
Esse ultimo exemplo é mais para tentar te mostrar o poder do shell e se você for criativo você já poderia por exemplo criar uma regra no firewall pra bloquear aquela porta ou matar o PID do socket, encaminhar um e-mail pra você mesmo ou qualquer outra coisa, a criatividade é o limite.
Loop While O loop while é outra coisa simples, ele vai executar até que uma condição deixe de ser verdadeira, falando ao contrário, ele vai executar até que uma condição se torne falsa.
Sintaxe:
Um exemplo simples de implementação do While:
Só ressaltando que a condição não necessariamente precisaria ser uma aritmetica, poderia qualquer verificação que retornasse true ou false, por exemplo esse script que verifica se o servidor apache2 parou de executar e se a condição for verdade ele executa automaticamente o daemon:
Foi empregado o comando id para verificar se o usuário estava executando era um usuário administrativo ou se era um usuário que responsável pelo daemon. Então temos o loop While Repare que o loop é um loop infinito que espera por 2 segundos antes de cada execução devido ao comando sleep.
Until: O Until funciona de uma forma diferente, ele irá executar até que a condição se torne verdadeira: Sintaxe:
Um exemplo simples:
FUNÇÔES:
Comando local: -> Use sempre o comando local para proteger todas as variáveis de uma função.
Exemplo:
Sempre colocar a s funções no início do programa, logo após as variáveis globais.
Funções só podem retornar números de ) a 255, usando o comando return
Funções podem retornar strings usando o comando echo.
Funções podem gravar variáveis globais mas evite fazer isso.
Funções não são nada além de pequenas subrotinas ou subscripts. É interessante adotar funções para modularizar o código tornando mais fácil a manutenção.
Funções de shell não retornam valor mas sim um status_code.
Existem duas formas de se declarar uma função:
E a outra forma é:
function hello_func(){ echo "Hello $1" }
function hello_input(){ echo $INPUT }
function parssing( $TESTE){ echo "holly $TESTE" } echo "[+] Starting Routine" hello_func $1 export INPUT=$2 hello_input
Argumentos -------
Vamos falar agora sobre argumentos. Argumentos são implementados em muitos programas seja para pedir help ou alterar a forma de operação, por exemplo:
O help foi foi um argumento passado ao programa ls
Agora vamos a um exemplo que melhor irá nos exibir isso:
Ao executar esse programa ele irá exibir o número de argumentos e os argumentos em suas devidas posições:
Então a partir disso é possível receber argumentos na execução do script podendo ser utilizado para deixar o programa não interativo, parametrizado como alguns dizem. Repare que $# exibe quantos argumentos foram dados. Isso poderia ser utilizado para chamar uma função de usage por exemplo:
Note que o $0 sempre exibe o path de execução, exatamente como o comando foi executado, para remover aquele PATH da exibição no programa, no nosso caso ./, você pode utilizar o comando basename da seguinte forma:
Uma outra forma que eu acredito ser melhor é usar o getopts:
Bom, no exemplo acima é importante notar um detalhe, é o seguinte:
As opções 'f:o:h' indicam qual o argumento que será passado, onde cada flag(f,o,h) que tem como sequencia o caracter ':' indica que será atribuido valor, as que não possuem ':' como sequencia não vão ser atribuidos valores, logo a $OPTARG não é atribuida.
O mesmo procedimento poderia ter sido utilizado com o while, case e o comando shitf, o resultado seria o mesmo. A diferença de usar a forma anterior citata nessa frase e utilizar o getopts é que o getopts não suporta argumentos longos(--argumento-longo), apenas curtos.
Vamos supor que você que executar vários scripts de dentro do seu programa, existem várias formas de fazer isso: Se referindo ao caminho absoluto do programa:
Ou se referindo ao caminho relativo do programa, porém nesse caso ambos vão ter que estar no mesmo diretório ou o programa que será inicializado terá que estar em algum subdiretório, claro que poderia ser feito aquela gambiarra de ir voltnado nos diretórios usando o comando cd mas acho isso feio.
Mas agora vamos supor que você tenha um programa que usa um arquivo de texto para se configurar com algumas variáveis. Exemplo do arquivo com as variáveis:
Exemplo do programa:
Agora executando o programa:
Antes de entrarmos de fato na elaboração de programas para pentest, vamos só dar um overview rápido em processamento de texto com os próprios programas no linux.
O primeiro programa que iremos dar uma olhada é o grep, este programa é utilizado para procurar strings em texto, a sintaxe delf é bem simples:
Por exemplo:
O grep é um comando bem parrudo e possui variantes como o fgrep e o egrep, podendo buscar até por expressões regulares, recomendo muito que você dê uma olhada nas man pages.
O comando cut faz um trabalho bem bacana cortando textos, exemplo de sintaxe:
Vamos pegar o mesmo arquivo anterior e pegar apenas os endereços IP's que acessar o servidor apache2:
Bom, a primeira parte desse paper fica por aqui, espero que tenham tirado algum proveito, os demais papers vão focar explicitamente no desenvolvimento de ferramentas para ajudar você no seu pentest.
"Don't comment bad code, rewrite it."
Fontes:
https://www.computerhope.com/unix/test.htm http://br.ccm.net/contents/320-linux-o-shell https://www.digitalocean.com/community/tutorials/how-to-read-and-set-environmental-and-shell-variables-on-a-linux-vps https://en.wikipedia.org/wiki/File_descriptor http://wiki.bash-hackers.org/commands/classictest
A estrutura dos sistemas linux possuem um padrão chamado de FHS, tende a ser uma árvore invertida, observe na imagem abaixo:
Existem três descritores default relacionados à input/output e error, muito utilizados em pipes ou sockets de rede. File Descriptor(FD) são números inteiros não negativos, abaixo segue a relação:
Existe uma tabela chamada Tabela Verdade, essa tabela mapeia as possibilidades combinatórias e o resultado sendo calculado por um operador lógico.