Lucas Possatti2016-12-19T14:05:49.949Zhttp://possatti.com.br/Lucas PossattiHexoGit Subtreeshttp://possatti.com.br/git-subtrees/2016-12-19T15:05:00.000Z2016-12-19T14:05:49.949Z<p>Vamos supor que você deseja importar um repositório Git para dentro de outro repositório Git. Como você faria isso? Vou te dizer que você tem duas opções: Submodules, ou Subtrees.</p>
<p>Os dois tem suas vantagens e desvantagens. A primeira vez que eu caí nessa necessidade, optei por Submodules, porque foi a primeira opção que encontrei, e Subtrees pareciam complicados. Hoje a minha opinião é o inverso disso. Submodules são fáceis de iniciar no repositório, mas difíceis de manter (principalmente se você trabalha com outras pessoas). Enquanto Subtrees parecem mais complicados quando você bate o olho, mas na realidade são muito mais fáceis de manter. Isso tudo é minha opnião, mas buscando na internet percebi que esse é o consenso.</p>
<p>E não vou afirmar que Subtrees são melhores que Submodules em todas as situações. <strong>Com certeza não são.</strong> Mas eu acredito que boa parte das vezes eles são a melhor opção.</p>
<p>Uma coisa a esclarecer é que o nome Subtree vêm de uma <a href="https://git-scm.com/book/en/v1/Git-Tools-Subtree-Merging" target="_blank" rel="external">estratégia de <em>merge</em></a> do Git, chamada Subtree (Woow). Que envolve fazer um <em>merge</em> aplicado a um diretório específico. E é exatamente essa estratégia de <em>merge</em> que é usada pelo <code>git subtree</code>. Mas a partir de agora, sempre que eu falar “Subtree”, estou me referindo ao comando <code>git subtree</code>.</p>
<p>Nos exemplos abaixo, nós vamos trabalhar com dois repositórios Git. Então para ficar claro, vou explicar como vou me referir a cada um deles. Quando eu falar “repositório <em>container</em>“, estou me referindo ao repositório mais abrangente, que vai conter a Subtree e todo o resto do seu código que não faz parte da Subtree. E quando eu falar “sub-repositório”, estou me referindo ao repositório que têm os arquivos que você quer puxar para dentro do repositório <em>container</em> (a Subtree).</p>
<p>O Git tem um comando <code>git subtree</code> integrado, porém talvez você se surpreenda com o fato de que ele não é um comando nativo como <code>git pull</code>, <code>git merge</code> e etc. Ele é um script criado pela comunidade que com o tempo ficou popular o suficiente para ser incluído dentro do Git. É possível usar Subtrees <a href="https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec#.qp8ny5efo" target="_blank" rel="external">sem usar o comando <code>git subtree</code></a>, mas é um pouco mais difícil.</p>
<h2 id="Usando-Subtrees"><a href="#Usando-Subtrees" class="headerlink" title="Usando Subtrees"></a>Usando Subtrees</h2><p>Existem quatro comandos importantes quando lidamos com Subtrees (na verdade três):</p>
<!-- Escrever também sobre o `git subtree split` e `git subtree merge`. Ou talvez só apontar que eles existem. -->
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">git remote add <subrepo-remoto> <subrepo-url></span><br><span class="line">git subtree add --prefix <subrepo-path> <subrepo-remoto> master --squash</span><br><span class="line">git subtree pull --prefix <subrepo-path> <subrepo-remoto> master --squash</span><br><span class="line">git subtree push --prefix <subrepo-path> <subrepo-remoto> master</span><br><span class="line"></span><br><span class="line"><span class="comment"># <subrepo-remoto>: Nome do remoto para o sub-repositório. (Exemplo: assets-do-joao)</span></span><br><span class="line"><span class="comment"># <subrepo-url>: Url do sub-repositório (Exemplo: github.com/joao/super-assets)</span></span><br><span class="line"><span class="comment"># <subrepo-path>: Diretório onde você vai "jogar" os arquivos do sub-repositório. (Exemplo: src/assets)</span></span><br></pre></td></tr></table></figure>
<p>Subtrees são algo relativamente novo para mim, mas eu estou usando há algum tempo no trabalho e vou falar do que entendi. Primeiro eu recomendo que os três últimos comandos sejam executados sempre da raiz do repositório <em>container</em>. Assim você não se perde colocando o caminho errado. E o primeiro comando é apenas para simplificar as operações seguintes. E repare que aqui eu estou usando o <em>branch</em> <code>master</code> para o sub-repositório. Mas se você tem uma necessidade diferente, troque o nome do <em>branch</em>.</p>
<p>Agora vamos ver cada um dos comandos com mais detalhes:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote add <subrepo-remoto> <subrepo-url></span><br></pre></td></tr></table></figure>
<p>O comando <code>git remote add</code> adiciona o sub-repositório aos remotos do nosso repositório <em>container</em>. (Sem nenhum mistério até aqui.)</p>
<!-- Lembrando que isso tem que ser feito para cada máquina que vai mexer com a Subtree. -->
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git subtree add --prefix <subrepo-path> <subrepo-remoto> master --squash</span><br></pre></td></tr></table></figure>
<p><code>git subtree add</code> inicia uma Subtree no nosso repositório. Deve ser usado uma única vez (a primeira). Ele puxa todos os <em>commits</em> do sub-repositório e comprime eles em um único <em>commit</em> (<em>squash</em>) e faz um <em>merge</em> desse <em>commit</em> com o nosso repositório. Após fazermos um <code>git push</code> do nosso repositório <em>container</em>, todos os arquivos da Subtree estarão vivendo dentro do nosso repositório no servidor. Então qualquer pessoa que fizer <code>git clone</code> ou <code>git pull</code> vai ter tudo pronto já, e não vai precisar nem se estressar em saber o que são Subtrees.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git subtree pull --prefix <subrepo-path> <subrepo-remoto> master --squash</span><br></pre></td></tr></table></figure>
<p><code>git subtree pull</code> puxa todos os <em>commits</em> do sub-repositório, comprime em um único <em>commit</em> (<em>squash</em>) e faz <em>merge</em> com nosso repositório. Após fazer <code>git push</code> todo mundo terá as alterações.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git subtree push --prefix <subrepo-path> <subrepo-remoto> master</span><br></pre></td></tr></table></figure>
<p><code>git subtree push</code> irá “caçar” todos os <em>commits</em> do nosso repositório <em>container</em> que mexem em alguma coisa no diretório da Subtree (<code><subrepo-path></code>); vai criar um novo <em>branch</em> temporário somente com esses <em>commits</em>; e vai mandar os <em>commits</em> desse <em>branch</em> para o servidor do sub-repositório. E agora a pessoa que mantém o sub-repositório terá nossas alterações.</p>
<p>A princípio pode ser difícil de entender o que o <code>git subtree push</code> está fazendo, mas você pode usar o comando <a href="http://stackoverflow.com/a/12819896" target="_blank" rel="external"><code>git subtree split</code></a> para ter uma ideia mais detalhada do que realmente está acontecendo.</p>
<h2 id="Recomendacoes"><a href="#Recomendacoes" class="headerlink" title="Recomendações"></a>Recomendações</h2><p>Quando você estiver trabalhando no repositório <em>container</em> e mexer em alguma coisa do sub-repositório paralelamente a alterações nos arquivos do repositório <em>container</em>, separe as coisas. Faça primeiro um <em>commit</em> contendo as alterações que pertencem a Subtree, e depois um <em>commit</em> com as alterações do repositório <em>container</em>. Isso não é 100% necessário, pois o comando <code>git subtree</code> vai conseguir dar conta de qualquer situação, mas ajuda na sua organização, pois as mensagens de cada <em>commit</em> ficarão mais intuitivas.</p>
<p>Use sempre a barra do Unix <code>/</code> (eu nunca me lembro qual é a barra, e qual é a contra barra T.T). Mesmo no Windows, use <code>/</code> para separar os diretórios. Uma vez eu usei com “a barra do Windows” (<code>\</code>), e aparentemente tinha funcionado, mas logo depois tive problemas. Então fica a dica.</p>
<h2 id="Concluindo"><a href="#Concluindo" class="headerlink" title="Concluindo"></a>Concluindo</h2><p>Se você quiser uma outra leitura, para entender melhor o assunto, eu recomendo que você leia o post da Atlassian sobre Subtrees chamado <a href="https://developer.atlassian.com/blog/2015/05/the-power-of-git-subtree/" target="_blank" rel="external"><em>The Power of Subtree</em></a>. Além do post mais aprofundado de Christophe Porteneuve: <a href="https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec#.qp8ny5efo" target="_blank" rel="external"><em>Mastering Git subtrees</em></a>. Esses dois materiais me ajudaram muito.</p>
Eu explico como usar o comando Git Subtree que pode ser usado para importar um repositório Git para dentro de outro repositório Git.
Elvis Operator - Angular 2http://possatti.com.br/angular2-elvis-operator/2016-11-05T01:18:00.000Z2016-11-05T02:41:59.505Z<p>Outro dia no trabalho, eu precisei colocar atributos de um objeto em um formulário usando o Angular 2. Porém eu não inicializava o objeto de imediato. O objeto só seria inicializado quando um serviço retornasse a reposta do servidor. E em função disso a <em>view</em> não renderizava, devido a um erro quando o Angular tentava acessar o atributo de um valor nulo. Buscando uma solução para o problema, eu acabei me deparando com o “<em>Elvis Operator</em>“ (<code>?.</code>). Que, devo admitir, me chamou bastante a atenção pelo nome curioso.</p>
<p>O <a href="https://en.wikipedia.org/wiki/Elvis_operator" target="_blank" rel="external"><em>Elvis Operator</em> não é um conceito novo</a>. Ele já é usado em algumas linguagens de programação, como C++, Groovy, PHP e outras. E antes que você me pergunte, eu já te aviso que ele não é um operador nativo do Javascript. Ele realmente só funciona dentro dos templates HTML do Angular 2. Vale a pena ler a <a href="https://angular.io/docs/ts/latest/guide/template-syntax.html#!#safe-navigation-operator" target="_blank" rel="external">documentação oficial</a>.</p>
<p>E note que há algum tempo atrás o <em>Elvis Operator</em> do Angular foi <a href="https://reviews.angular.io/R6:4cfff4148523b67eb204225f89bff3485e44ce4f" target="_blank" rel="external">renomeado</a> para “<em>Safe Navigation Operator</em>“ (Operador de Navegação Segura), que é um nome muito mais chato, convenhamos… <em>Elvis Operator</em> é um nome muito mais legal. Só dizendo.</p>
<!--
**Obs:** Se eu entendi certo, talvez *Elvis Operator* seja sequer o termo correto para essa operação. Possivelmente o nome mais apropriado para essa operação seja *null-safe dereferencing*. Aparentemente existe uma [confusão entre os dois termos][the-true-elvis].
[the-true-elvis]: http://mail.openjdk.java.net/pipermail/coin-dev/2009-July/002089.html
-->
<p>No Angular 2, esse operador é usado para acessar um atributo de um objeto, apenas quando o objeto não é nulo. Enquanto ele for nulo, nada é acessado. Assim nós não nos deparamos com um erro, e a aplicação continua funcionando normalmente. Imediatamente quando o valor deixa de ser nulo, o atributo será acessado e renderizado na tela.</p>
<p>Para obter esse efeito poderíamos usar uma expressão como <code>carro && carro.cor</code>, dessa forma <code>carro.cor</code> seria acessado apenas se <code>carro</code> não fosse nulo. Essa expressão funciona, porém utilizando o <em>Elvis Operator</em> podemos simplificar a expressão para apenas <code>carro?.cor</code>.</p>
<p>Vamos a um exemplo mais completo. Suponhamos um componente como o abaixo:</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">@Component({</span><br><span class="line"> moduleId: <span class="keyword">module</span>.id,</span><br><span class="line"> selector: 'example',</span><br><span class="line"> templateUrl: 'example.component.html'</span><br><span class="line">})</span><br><span class="line">export class ExampleComponent implements OnInit {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> carro: Carro;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">constructor</span>(private exampleService: ExampleService) {}</span><br><span class="line"></span><br><span class="line"> ngOnInit() {</span><br><span class="line"> <span class="comment">// Busca a instância de carro no servidor.</span></span><br><span class="line"> <span class="keyword">this</span>.exampleService.getCarro(<span class="number">1</span>)</span><br><span class="line"> .subscribe(carro => <span class="keyword">this</span>.carro = carro);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>E que usa o seguinte template HTML:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">h3</span>></span>Detalhes do Carro<span class="tag"></<span class="name">h3</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>ID: {{ carro.id }}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>Marca: {{ carro.marca }}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>Modelo: {{ carro.modelo }}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>Cor: {{ carro.cor }}<span class="tag"></<span class="name">p</span>></span></span><br></pre></td></tr></table></figure>
<p>Ao iniciar a aplicação vamos ter um erro, pois o Angular tentará ler a propriedade <code>id</code> de <code>carro</code>, sendo que inicialmente <code>carro</code> é nulo, pois quando o componente é renderizado na tela, não deu tempo do <em>browser</em> terminar a requisição HTTP e buscar o objeto. Teremos uma mensagem semelhante ao seguinte: <code>cannot read property 'id' of undefined</code>.</p>
<p>Podemos resolver isso, ao utilizar o <em>Elvis Operator</em> (<code>?.</code>). No exemplo abaixo, ele verifica se <code>carro</code> é nulo: se for nulo, ele <em>deixa quieto</em>; porém se carro realmente for um objeto, só então, ele tentará acessar os respectivas atributos de <code>carro</code>.</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">h3</span>></span>Detalhes do Carro<span class="tag"></<span class="name">h3</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>ID: {{ carro?.id }}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>Marca: {{ carro?.marca }}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>Modelo: {{ carro?.modelo }}<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"><<span class="name">p</span>></span>Cor: {{ carro?.cor }}<span class="tag"></<span class="name">p</span>></span></span><br></pre></td></tr></table></figure>
<p>Porém é necessário ter cuidado ao usar o <em>Elvis Operator</em> juntamente com o <em>two-way data binding</em>, o que não é suportado. Isso pode acontecer ao usarmos a diretiva <code>ngModel</code> em um formulário, por exemplo.</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">h3</span>></span>Cadastrar novo Carro<span class="tag"></<span class="name">h3</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">form</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span>></span>Marca<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> [(<span class="attr">ngModel</span>)]=<span class="string">"carro?.marca"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span>></span>Modelo<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> [(<span class="attr">ngModel</span>)]=<span class="string">"carro?.modelo"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span>></span>Cor<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> [(<span class="attr">ngModel</span>)]=<span class="string">"carro?.cor"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">form</span>></span></span><br></pre></td></tr></table></figure>
<p>No exemplo acima teremos um erro: <code>The '?.' operator cannot be used in the assignment at column 5 in [carro?.marca=$event] in ExampleComponent</code>. Isso acontece pois, ao fazer o <em>two-way binding</em>, o Angular precisa colocar valores dentro de <code>carro?.marca</code>, e isso não é suportado usando o <em>Elvis Operator</em> (ainda). É possível contornar o problema quebrando o <code>[(ngModel)]</code> em duas partes, como no exemplo a seguir.</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">form</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span>></span>Marca<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> [<span class="attr">ngModel</span>]=<span class="string">"carro?.marca"</span> (<span class="attr">ngModelChange</span>)=<span class="string">"carro.marca=$event"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span>></span>Modelo<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> [<span class="attr">ngModel</span>]=<span class="string">"carro?.modelo"</span> (<span class="attr">ngModelChange</span>)=<span class="string">"carro.modelo=$event"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">label</span>></span>Cor<span class="tag"></<span class="name">label</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> [<span class="attr">ngModel</span>]=<span class="string">"carro?.cor"</span> (<span class="attr">ngModelChange</span>)=<span class="string">"carro.cor=$event"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">form</span>></span></span><br></pre></td></tr></table></figure>
<p>Isso funciona, mas na <em>minha opinião</em> fica verboso demais. E no final das contas, acaba parecendo uma gambiarra. Repare também que existe uma <em>issue</em> aberta para que o <a href="https://github.com/angular/angular/issues/7697" target="_blank" rel="external"><em>Elvis Operator</em> seja suportado pelo <em>two-way data binding</em></a>. (Quem sabe no futuro ele não funciona com o <code>[(ngModel)]</code>?)</p>
<p>De qualquer forma, no meu trabalho, ao invés de usar o <em>Elvis Operator</em>, eu achei mais sucinto e elegante criar um objeto vazio para ser temporariamente renderizado, enquanto o objeto com os dados verdadeiros ainda não é carregado. Para isso eu alterei o meu componente para o seguinte:</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">@Component({</span><br><span class="line"> moduleId: <span class="keyword">module</span>.id,</span><br><span class="line"> selector: 'example',</span><br><span class="line"> templateUrl: 'example.component.html'</span><br><span class="line">})</span><br><span class="line">export class ExampleComponent implements OnInit {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Um objeto vazio para servir de "placeholder".</span></span><br><span class="line"> <span class="keyword">private</span> carro: Carro = <span class="keyword">new</span> Carro();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">constructor</span>(private exampleService: ExampleService) {}</span><br><span class="line"></span><br><span class="line"> ngOnInit() {</span><br><span class="line"> <span class="keyword">this</span>.exampleService.getCarro(<span class="number">1</span>)</span><br><span class="line"> .subscribe(carro => <span class="keyword">this</span>.carro = carro);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Assim, a tela é carregada usando os atributos do objeto vazio. Porém, logo que o objeto real chega, a tela é alterada para refletir os valores do objeto verdadeiro. E isso <strong>sem</strong> usar o <em>Elvis Operator</em>.</p>
<p>Concluindo, o <em>Elvis Operator</em> pode ser muito útil em algumas situações. Mas, pelo menos na <strong>minha opinião</strong>, acaba com cara de gambiarra. Apesar de que, se ele está presente na documentação oficial com certeza tem usos legítimos. Mas eu sinto que uma solução mais simples e elegante é renderizar um objeto temporário na tela que será substituído pelo objeto verdadeiro depois.</p>
<!--
Links não utilizados:
[cheatsheet]: https://angular.io/docs/ts/latest/guide/cheatsheet.html
[stackoverflow-question]: http://stackoverflow.com/questions/35161789/correct-use-of-elvis-operator-in-angular2-for-dart-components-view
[elvis-on-syntaxsuccess]: http://www.syntaxsuccess.com/viewarticle/elvis-operator-in-angular-2.0
-->
No Angular 2, o Elvis Operator, é um operador usado para acessar uma propriedade de um objeto, apenas quando ele não é nulo.
Atualização para o Angular 2 Finalhttp://possatti.com.br/angular-update/2016-10-15T16:27:00.000Z2016-10-15T17:16:29.020Z<p>Na empresa em que estou trabalhando, nós estamos construindo uma aplicação usando o Angular 2 no front-end. Nós iniciamos o projeto na versão RC3 do Angular 2 (<code>2.0.0-rc3</code>), e agora mais recentemente nós atualizamos para a versão Final do Angular 2 (<code>2.0.0</code>). Fazer isso (pelo menos para mim) foi uma tarefa mais difícil do que eu esperava. Então eu resolvi escrever um passo a passo, enquanto eu aprendia a atualizar o projeto.</p>
<p>Como eu disse, fazer a atualização pode dar um pouco de trabalho. Algumas coisas no Router mudaram e isso foi o que mais me trouxe dificuldade. Além de que agora Módulos são usados para cada “pacote de funcionalidade”. Você pode conferir <a href="https://angular.io/resources/live-examples/router/ts/plnkr.html" target="_blank" rel="external">esse Plnkr</a> e o <a href="https://angular.io/docs/ts/latest/quickstart.html" target="_blank" rel="external">“Quickstart”</a> para ter uma ideia do que deve ser feito. No passo-a-passo abaixo, eu vou me referir a esses dois o tempo inteiro, então eu espero que você pelo menos dê uma olhada neles antes.</p>
<h2 id="Processo-de-atualizacao-do-angular"><a href="#Processo-de-atualizacao-do-angular" class="headerlink" title="Processo de atualização do angular"></a>Processo de atualização do angular</h2><ol>
<li>Colocar os arquivos na nova convenção de nomes: <code>*.component.{ts,html}</code>, <code>*.service.ts</code>, <code>*.routing.ts</code>, <code>*.guard.ts</code>, etc. (Opcional)</li>
<li>Colocar o <code>package.json</code> do <a href="https://angular.io/docs/ts/latest/quickstart.html" target="_blank" rel="external">“Quickstart”</a> no lugar do <code>package.json</code> atual e executar <code>npm install</code>.</li>
<li>Possivelmente, você deve deletar a pasta “typings” e rodar <code>npm run postinstall</code>, se erros não aparecerem nos <code>*.ts</code> do projeto. Porque erros vão aparecer!</li>
<li>Seguir o <a href="https://angular.io/resources/live-examples/router/ts/plnkr.html" target="_blank" rel="external">exemplo</a> para configurar as rotas.<ul>
<li>Muitos <code>*.component.ts</code> terão erro, pois <code>ROUTER_DIRECTIVES</code> não existe mais e deve ser retirado de todo o código.</li>
<li><code>Router</code>, <code>ActivatedRoute</code> e <code>Params</code> continuam sendo importados normalmente de <code>@angular/router</code>.</li>
<li>Diretivas como o <code>routerLink</code> são inseridas pelo RouterModule aparentemente, mas não tenho certeza.</li>
</ul>
</li>
<li>Acertar também os arquivos de rotas (<code>*.routing.ts</code>):<ul>
<li>Não existe mais o <code>RouterConfig</code>, nem o <code>provideRouter</code>.</li>
<li><code>Routes</code> substitui <code>RouterConfig</code>.</li>
<li>No lugar de <code>terminal: true</code> (junto com <code>redirectTo: ...</code>), agora é usado <code>pathMatch: 'full'</code>.</li>
<li>É necessário exportar o objeto <code>whateverRouting</code>.</li>
<li>E o Router de Login exporta <code>authProviders</code> contendo os “Guards” e o serviço de login. (acho que isso é opcional.)</li>
</ul>
</li>
<li>É recomendado criar módulos for funcionalidade (ex: <code>app/alunos</code>, <code>app/profs</code>, etc). O módulo raíz (<code>app.module.ts</code>) importa os outros módulos, na seção <code>imports</code>. Fazer isso não é necessário. É possível ter um único módulo, mas ter múltiplos módulos está sendo muito usado. Ao optar por não usar esse modelo, o <code>app.module.ts</code> pode rapidamente ficar lotado de <em>Components</em> e <em>Services</em>. Independente da escolha, pelo menos um módulo deve ser criado para a aplicação, chamado <code>app.module.ts</code>.<ul>
<li>Cada Módulo importa os módulos que irá precisar, como: <code>HttpModule</code>, <code>FormsModule</code>, <code>CommomMondule</code>.</li>
<li>Cada Módulo importa (<code>imports</code>) as rotas pertencentes àquele módulo. Ex: <code>alunos.module.ts</code> importa <code>alunos.routing.ts</code>.</li>
<li>Cada Módulo registra seus componentes na seção <code>declarations</code>.</li>
<li>Cada Módulo registra os serviços que fornece na seção <code>providers</code>.</li>
<li><code>app.module.ts</code> deve importar <code>BrowserModule</code>, e deve ter uma seção <code>bootstrap: [ AppComponent ]</code>.</li>
</ul>
</li>
<li>Criar um <code>main.ts</code>. Tudo é igual ao <a href="https://angular.io/resources/live-examples/router/ts/plnkr.html" target="_blank" rel="external">exemplo</a>.</li>
<li>Atualizar o <code>systemjs.config.js</code>. (Também igual ao <a href="https://angular.io/resources/live-examples/router/ts/plnkr.html" target="_blank" rel="external">exemplo</a>.)</li>
<li>Nos templates HTML, não é mais possível usar <code>#id=index</code>, ou qualquer <code>#</code> dentro do <code>*ngFor</code>. <code>let</code> deve ser usado.</li>
</ol>
<h2 id="Exemplo-de-Modulo"><a href="#Exemplo-de-Modulo" class="headerlink" title="Exemplo de Módulo"></a>Exemplo de Módulo</h2><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// whatever.module.ts</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> { CommonModule } from <span class="string">'@angular/forms'</span>;</span><br><span class="line"><span class="keyword">import</span> { FormsModule } from <span class="string">'@angular/forms'</span>;</span><br><span class="line"><span class="keyword">import</span> { HttpModule } from <span class="string">'@angular/http'</span>; <span class="comment">// '@angular/http' ?</span></span><br><span class="line"><span class="keyword">import</span> { whateverRouting } from <span class="string">'./whatever.routing'</span>;</span><br><span class="line"></span><br><span class="line">@NgModule({</span><br><span class="line"> imports: [ <span class="comment">// `imports`: módulos que dependemos.</span></span><br><span class="line"> CommonModule, <span class="comment">// Diretivas como `ngFor` e `ngIf`.</span></span><br><span class="line"> FormsModule, <span class="comment">// Template Driven Forms.</span></span><br><span class="line"> HttpModule, <span class="comment">// Para requisições http.</span></span><br><span class="line"> whateverRouting, <span class="comment">// Rotas desse módulo.</span></span><br><span class="line"> ...</span><br><span class="line"> ],</span><br><span class="line"> declarations: [ <span class="comment">// `declarations`: components, directives e pipes.</span></span><br><span class="line"> WhateverComponent,</span><br><span class="line"> WhateverPipe,</span><br><span class="line"> ...</span><br><span class="line"> ],</span><br><span class="line"> providers: [ <span class="comment">// `providers`: services.</span></span><br><span class="line"> WhateverService,</span><br><span class="line"> ...</span><br><span class="line"> ],</span><br><span class="line">})</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> WhateverModule {}</span><br></pre></td></tr></table></figure>
<h2 id="Exemplo-de-rotas"><a href="#Exemplo-de-rotas" class="headerlink" title="Exemplo de rotas"></a>Exemplo de rotas</h2><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// whatever.routing.ts</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> { ModuleWithProviders } from <span class="string">'@angular/core'</span>;</span><br><span class="line"><span class="keyword">import</span> { Routes, RouterModule } from <span class="string">'@angular/router'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> { WhateverComponent } from <span class="string">'./whatever.component'</span>;</span><br><span class="line"><span class="keyword">import</span> { WhateverGuard } from <span class="string">'../../whatever.guard'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> whateverRoutes: Routes = [</span><br><span class="line"> { path: <span class="string">''</span>, redirectTo: <span class="string">'/whatever'</span>, pathMatch: <span class="string">'full'</span> },</span><br><span class="line"> { path: <span class="string">'whatever'</span>, component: WhateverComponent, canActivate: [ WhateverGuard ] },</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> whateverRouting: ModuleWithProviders = RouterModule.forChild(whateverRoutes);</span><br></pre></td></tr></table></figure>
<p>O router de login é um pouco diferente:</p>
<figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ...</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> authProviders = [</span><br><span class="line"> AuthGuard,</span><br><span class="line"> AuthService</span><br><span class="line">];</span><br></pre></td></tr></table></figure>
<h2 id="Exemplo-de-uso-de-Router-dentro-de-um-Component"><a href="#Exemplo-de-uso-de-Router-dentro-de-um-Component" class="headerlink" title="Exemplo de uso de Router dentro de um Component"></a>Exemplo de uso de <em>Router</em> dentro de um <em>Component</em></h2><p>Os <em>imports</em> que eu observei do <em>router</em>:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// whatever.component.ts</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> { Router, ActivatedRoute, Params } <span class="keyword">from</span> <span class="string">'@angular/router'</span>;</span><br><span class="line"></span><br><span class="line">@Component({...})</span><br><span class="line"><span class="keyword">export</span> <span class="class"><span class="keyword">class</span> <span class="title">WhateverComponent</span> </span>{</span><br><span class="line"> <span class="comment">// Injestão de dependências.</span></span><br><span class="line"> <span class="keyword">constructor</span>(</span><br><span class="line"> private service: WhateverService,</span><br><span class="line"> private route: ActivatedRoute,</span><br><span class="line"> private router: Router</span><br><span class="line"> ) {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
Na empresa onde eu trabalho, tivemos que atualizar para a versão final do Angular 2. Neste post eu resumo o que eu aprendi.
Curso de githttp://possatti.com.br/curso-de-git/2016-07-12T08:32:52.000Z2016-07-12T11:24:52.394Z<p>Após minha saída do LEDS, com a ajuda dos professores do IFES, eu criei uma série de vídeo tutoriais sobre o Git. Nos vídeos eu explico sobre as funções mais básicas, e algumas mais complexas. Em todos os vídeos eu me preocupei em explicar as coisas de forma que um iniciante conseguisse trabalhar tranquilamente usando o Git após o curso. E eu também falo um pouco sobre <em>workflows</em> e as formas como você pode trabalhar em equipe ao final.</p>
<p>Criar esse curso foi uma experiência totalmente nova para mim. E nos primeiros vídeos eu estava incrivelmente nervoso, mas consegui melhorar um pouco ao longo dos vídeos.</p>
<p>Eu queria ter editado cada um dos vídeos que eu gravei em meu computador, para cortar algumas partes desnecessárias e alguns erros, e para dar uma polida nos vídeos. Mas, infelizmente, eu não consegui editar os vídeos de forma satisfatória. E como já estava demorando muito, resolvemos publicar os vídeos da forma que foi possível (sem edição).</p>
<p>Então, apesar de não estar perfeito, vos apresento o <a href="https://youtu.be/TC5r2qGiqcI?list=PLo7sFyCeiGUdIyEmHdfbuD2eR4XPDqnN2" target="_blank" rel="external">curso</a>.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/TC5r2qGiqcI?list=PLo7sFyCeiGUdIyEmHdfbuD2eR4XPDqnN2" frameborder="0" allowfullscreen></iframe>
Após minha saída do LEDS, com a ajuda dos professores do IFES, eu criei uma série de vídeo tutoriais sobre o Git.
Sincaphttp://possatti.com.br/sincap/2016-07-12T07:54:40.000Z2016-07-12T08:00:04.656Z<p><img src="/images/sincap-reportagem.jpg" alt=""></p>
<p>Durante a faculdade no IFES campus Serra, eu tive a oportunidade de participar do <a href="http://leds.sr.ifes.edu.br/" target="_blank" rel="external">LEDS</a>. No tempo em que estive lá, eu trabalhei principalmente em um projeto chamado <a href="http://leds.sr.ifes.edu.br/portfolio/sincap/" target="_blank" rel="external">Sincap</a>. Que foi um sistema para auxiliar no processo de doações de córneas do estado do Espírito Santo.</p>
<p>Durante o seu desenvolvimento, o Sincap apareceu em uma <a href="http://www.gazetaonline.com.br/_conteudo/2014/08/noticias/cidades/1495041-alunos-do-ifes-criam-sistema-de-captacao-de-cornea.html" target="_blank" rel="external">reportagem no jornal A Gazeta</a>, e uma <a href="http://www.folhavitoria.com.br/videos/2014/08/2934103-011-captacao-de-orgaos-mais-rapida.html" target="_blank" rel="external">reportagem no jornal ES NO AR, na TV Vitória</a>. E também foi <a href="http://leds.sr.ifes.edu.br/sincap-e-premiado-na-11a-semana-estadual-de-ciencia-e-tecnologia/" target="_blank" rel="external">premiado na 11ª Semana Estadual de Ciência e Tecnologia</a>.</p>
<p>O processo natural para a doação de córneas no Espírito Santo é todo feito por telefonemas e formulários preenchidos a mão, que são enviados para lá e para cá através de Fax. O Sincap foi criado como uma tentativa de modernizar e agilizar esse processo.</p>
<p>Infelizmente, pelo que eu conversei com amigos que ainda estão no LEDS, o Sincap ainda não foi implantado, em função de um pouco de burocracia e um desandamento nas negociações.</p>
<p>É uma pena. Mas independente do seu fim, eu aprendi bastante com esse projeto. E tenho certeza que a equipe inteira também. Trabalhar com o Sincap foi a primeira experiência que eu tive de trabalhar em um projeto real. Nós tínhamos que fazer a parte de análise e projeto do sistema, fazer entrevistas com o cliente, implementar, testar o sistema, e etc. Cada membro da equipe trabalhava com um pouco de cada coisa.</p>
<p>O Sincap foi praticamente a minha primeira vez trabalhando em um sistema Web. Eu aprendi muita coisa trabalhando nele. Nós usamos Java e <a href="https://spring.io" target="_blank" rel="external">Spring Framework</a> para construir o servidor Web. <a href="http://hibernate.org/orm/" target="_blank" rel="external">Hibernate</a> para a persistência de dados. O <a href="https://maven.apache.org/" target="_blank" rel="external">Maven</a> para gerenciar as dependências e as <em>builds</em> do projeto. E para a parte de <em>front-end</em>, um dos professores comprou um template de interface de administrador (baseado em <a href="http://getbootstrap.com/" target="_blank" rel="external">bootstrap</a>) que nós usávamos para construir as telas. Também chegamos ao ponto de construir um servidor de integração contínua usando <a href="https://jenkins.io/index.html" target="_blank" rel="external">Jenkins</a>, apesar de que ele não era realmente usado enquanto estive lá. E usávamos o <a href="https://git-scm.com" target="_blank" rel="external">Git</a> para o controle de versão.</p>
<p>Foram muitas as lições aprendidas. E não era tudo um mar de rosas, mas no geral foi bom trabalhar no projeto. :)</p>
O Sincap foi um projeto em que trabalhei durante o meu tempo no LEDS.
Minha experiência no LEDShttp://possatti.com.br/leds/2016-07-12T06:10:53.000Z2016-07-12T07:56:21.570Z<p>Durante a faculdade no IFES campus Serra, eu fiz parte do LEDS. Com a minha saída deste laboratório, eu publiquei um post no blog do LEDS, e nele eu conto sobre o que eu vivi ali dentro.</p>
Este é um post que publiquei no blog do LEDS, como minha despedida. No post eu conto sobre o que vivi dentro do laboratório.
Tutorial de Shell Scripthttp://possatti.com.br/shell-script/2016-06-30T15:41:53.000Z2016-07-12T08:03:56.131Z<p>Neste post vou explicar um pouco de tudo o que eu sei sobre shell script. Eu comecei a usar shell script porque eu queria automatizar algumas tarefas minhas. E meu gosto pela linguagem começou pela minha fascinação. Eu lia alguns scripts, mas não entendia nada! Além disso eu percebia o potencial da linguagem, as coisas que eu poderia criar com aquilo.</p>
<p>Shell script é uma linguagem com uma sintaxe extranhíssima e muito diferente de qualquer outra linguagem que eu conhecia antes. Eu tinha experiência com linguagens como Python, Java, um pouco de C e outras. E estudando shell script eu aprendi muita coisa que eu não conhecia, e que pode ser aplicado em outras linguagens. Então depois de estudar, sinto que conheço mais sobre programação de forma geral. Estudar shell script também me permitiu conhecer melhor como funciona a arquitetura de programas e processos do Linux. Antes disso, eu não sabia o que era <code>stdout</code> e <code>stdin</code> por exemplo. E hoje eu percebo que esse é um conhecimento bem útil e que eu não tinha antes.</p>
<p>Apesar da sintaxe estranha, shell script é uma linguagem forte e capaz de muita coisa. Imagine o seguinte. Em seu computador você tem programas de todos os tipos. Alguns escritos em C, outros que foram escritos em Python, Java, Perl e etc. Agora imagine utilizar o poder de cada programa desses em coletivo para construir algo maior. É isso que você vai fazer. Usando shell script você irá orquestrar chamadas a esses programas, para cumprir um objetivo específico. Uau, isso é poderoso. É claro que você pode fazer isso em qualquer linguagem, mas shell script foi feito para isso!</p>
<p>Se você se interessou até aqui, continue lendo. Garanto que você vai aprender algo interessante. Porém, antes de começar, algumas sugestões:</p>
<ul>
<li>Se você nunca aprendeu programação antes, te sugiro fortemente, e <em>enfáticamente</em> que você não comece por shell script. Aprenda Python, C/C++, Java, PHP ou qualquer outra linguagem e depois volte aqui. Sério!</li>
<li>E para seguir com o que eu vou explicar aqui, você deve estar um pouco acostumado a usar o terminal. Do contrário você vai ter um pouco de dificuldade.</li>
</ul>
<p>Você irá perceber que muitas vezes eu vou ser breve e sucinto em certos assuntos. Principalmente aqueles que você provavelmente já viu em outras linguagens de programação. Outras vezes será porque não tive tempo de expandir e escrever da melhor forma possível. Se você perceber que eu não abordei algo importante, ou se algum dos exemplos está errado, ou se tem qualquer outra sugestão, por favor, deixe um comentário.</p>
<p>Vamos começar.</p>
<h2 id="Sumario"><a href="#Sumario" class="headerlink" title="Sumário"></a>Sumário</h2><ul>
<li><a href="#Diferentes-Shells">Diferentes Shells</a></li>
<li><a href="#Hello-World">Hello World</a></li>
<li><a href="#O-basico">O básico</a><ul>
<li><a href="#Shebang">Shebang (#!)</a></li>
<li><a href="#Comandos-uteis">Comandos úteis</a></li>
<li><a href="#Manuais">Manuais</a></li>
<li><a href="#Wildcards-Globs">Wildcards (Globs)</a></li>
</ul>
</li>
<li><a href="#Variaveis">Variáveis</a></li>
<li><a href="#Substituicao-de-comandos">Substituição de comandos</a></li>
<li><a href="#Condicionais">Condicionais</a></li>
<li><a href="#Switch-case">Switch case</a></li>
<li><a href="#Loops">Loops</a><ul>
<li><a href="#For">For</a></li>
<li><a href="#While">While</a></li>
</ul>
</li>
<li><a href="#Argumentos">Argumentos</a></li>
<li><a href="#Pipe-e-redirecao">Pipe e redireção</a></li>
<li><a href="#Funcoes">Funções</a></li>
<li><a href="#Matematica">Matemática</a></li>
<li><a href="#Manipulacao-de-texto">Manipulação de texto</a></li>
<li><a href="#Conclusao">Conclusão</a></li>
</ul>
<h2 id="Diferentes-Shells"><a href="#Diferentes-Shells" class="headerlink" title="Diferentes Shells"></a>Diferentes Shells</h2><p>Existem muitas <a href="https://en.wikipedia.org/wiki/Unix_shell" target="_blank" rel="external">Shells</a> diferentes. Muitas mesmo! E cada uma delas tem uma linguagem de script diferente. Apesar disso a maioria das Shells apresentam algum nível de compatibilidade com a <a href="https://en.wikipedia.org/wiki/Bourne_shell" target="_blank" rel="external">Bourne Shell</a> (<code>sh</code>), que foi uma das primeiras a existir. Algumas das Shells mais usadas são:</p>
<ul>
<li>sh (<a href="https://en.wikipedia.org/wiki/Bourne_shell" target="_blank" rel="external">Bourne shell</a>)</li>
<li>bash (<a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)" target="_blank" rel="external">Bourne-Again shell</a>)</li>
<li>dash (<a href="https://en.wikipedia.org/wiki/Almquist_shell" target="_blank" rel="external">Debian Almquist shell</a>)</li>
<li>fish (<a href="https://en.wikipedia.org/wiki/Friendly_interactive_shell" target="_blank" rel="external">friendly interactive shell</a>. minha favorita)</li>
<li>zsh (<a href="https://en.wikipedia.org/wiki/Z_shell" target="_blank" rel="external">Z shell</a>. Muita gente gosta dessa para usar no dia-a-dia)</li>
<li>ksh (<a href="https://en.wikipedia.org/wiki/Korn_shell" target="_blank" rel="external">Korn shell</a>)</li>
<li>csh (<a href="https://en.wikipedia.org/wiki/C_shell" target="_blank" rel="external">C shell</a>)</li>
<li>… ad infinitum.</li>
</ul>
<p>A Shell mais popular provavelmente é o Bash. Se você usa Ubuntu e não sabe qual é a sua Shell, ela provavelmente é o Bash. Ainda assim, algumas pessoas preferem outras Shells para usar interativamente. Eu prefiro o Fish, por exemplo, e conheço muitas pessoas que preferem utilizar o Zsh.</p>
<p>Apesar de todas as variações, a maioria delas possuem um subconjunto de operações e de sintáxe iguais ao do <code>sh</code>. Por isso vou ensinar <code>sh</code> puro aqui. Variações como o <code>bash</code> adicionam algumas coisas legais à linguagem, mas que não são compatíveis com as outras shells. Se você se restringir a <code>sh</code> puro, seu código vai funcionar na maioria das outras shells. (Não todas. O <code>fish</code>, por exemplo, não é compatível. Já sofri muito com isso. T.T)</p>
<p>No Ubuntu, quando você usa o <code>sh</code>, na verdade você está usando o <code>dash</code>. Mas… Whatever. O <code>dash</code> foi feito apenas para ser um versão mais rápida e leve da Bourne Shell, e é totalmente compatível com a Bourne shell (até onde eu sei).</p>
<h2 id="Hello-World"><a href="#Hello-World" class="headerlink" title="Hello World"></a>Hello World</h2><p>Se você nunca mexeu com shell script antes, me acompanhe para fazer um Hello World. Abra o terminal (<code>Ctrl+Shift+T</code>), e use seu editor de texto favorito para criar um novo arquivo arquivo de texto. Aqui eu vou usar o <code>nano</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ nano script.sh <span class="comment"># Nano é um editor de texto, use qualquer um que você prefira</span></span><br></pre></td></tr></table></figure>
<p>Usando seu editor de texto, digite o seguinte código:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="built_in">echo</span> Hello World</span><br></pre></td></tr></table></figure>
<p>A primeira linha é um shebang (<code>#!</code>) e identifica o tipo de script que estamos criando, vou explicar melhor sobre o shebang depois. E na segunda linha, <code>echo</code> irá imprimir “Hello World”. Agora, salve e feche o editor de texto. (No <code>nano</code> você usa <code>Ctrl+O</code> (letra Ó) para salvar, e <code>Ctrl+X</code> para sair.) Depois, digite o comando seguinte no mesmo terminal e você verá o <code>Hello World</code>:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sh script.sh</span><br><span class="line">Hello world</span><br></pre></td></tr></table></figure>
<p><em>Voilà</em>! Agora você já sabe como criar e executar um shell script. Você já pode pegar seu certificado de “Shell Script Noob” na recepção e ir embora, ou continuar com o resto do guia para ganhar o certificado de “Shell Script Master”. ;)</p>
<h2 id="O-basico"><a href="#O-basico" class="headerlink" title="O básico"></a>O básico</h2><p>No seu uso mais básico, shell script é usado para executar um comando após o outro. Igual que você estivesse usando o terminal, e digitando um comando após o outro. Mas colocando esses comandos em um script, você pode automatizar suas tarefas.</p>
<p>Por exemplo, depois de formatar meu computador eu tenho <a href="https://github.com/possatti/my-setup-scripts" target="_blank" rel="external">vários scripts</a> que instalam algumas coisas que eu costumo usar no dia-a-dia, exemplo:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line">sudo apt-get -y install git</span><br><span class="line">sudo apt-get -y install python-pip</span><br><span class="line">sudo apt-get -y install fish</span><br><span class="line">sudo apt-get -y install guake</span><br><span class="line">sudo apt-get -y install htop</span><br><span class="line">sudo apt-get -y install tree</span><br><span class="line">sudo apt-get -y install transmission</span><br><span class="line">sudo apt-get -y install texlive-latex-base</span><br></pre></td></tr></table></figure>
<p>Quando eu executar o script acima, todos esses programas serão instalados pelo <code>apt-get</code>. Isso me poupa o trabalho de ter que me lembrar e de ter que digitar manualmente cada um desses comandos.</p>
<p>Você também pode executar mais de um comando na mesma linha, separando os comandos por <code>;</code>. O <code>;</code> é opcional no final de uma linha.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> -n <span class="string">"Hello"</span>; <span class="built_in">echo</span> -n <span class="string">"World"</span>; <span class="built_in">echo</span> <span class="string">"!"</span>;</span><br></pre></td></tr></table></figure>
<p>E a indentação também não importa.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> -n <span class="string">"Hello"</span></span><br><span class="line"> <span class="built_in">echo</span> -n <span class="string">"World"</span></span><br><span class="line"> <span class="built_in">echo</span> -n <span class="string">"!"</span></span><br></pre></td></tr></table></figure>
<p>Mas, por favor, indente seu código de forma intuitiva e organizada. Não é só porque você está usando a linguagem mais feia já inventada que você precisa escrever o código mais feio já inventado.</p>
<h3 id="Shebang"><a href="#Shebang" class="headerlink" title="Shebang (#!)"></a>Shebang (#!)</h3><p>No linux, é muito comum você colocar um <a href="https://pt.wikipedia.org/wiki/Shebang" target="_blank" rel="external">shebang</a> (<code>#!</code>) na primeira linha de um script. Ele serve para que seu computador identifique qual programa roda aquele script. Ele só funciona se for a primeira linha do arquivo. Aqui estão alguns exemplos:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/sh</span><br><span class="line">#!/usr/bin/python</span><br><span class="line">#!/usr/bin/ruby</span><br><span class="line">#!/bin/bash</span><br><span class="line">#!/usr/bin/perl</span><br></pre></td></tr></table></figure>
<p>Agora você já percebeu que ele toma o formato <code>#!</code> + <code><executável></code>. Sendo que o executável é o programa que vai rodar o seu script. Se você não colocar um shebang no seu script, você vai precisar de executar ele da seguinte forma:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sh script.sh</span><br></pre></td></tr></table></figure>
<p>Se você colocar o devido shebang você pode fazer:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ chmod +x script.sh <span class="comment"># Apenas da primeira vez, para transformar o arquivo em executável</span></span><br><span class="line">$ ./script.sh <span class="comment"># Se você estiver no mesmo diretório que o script</span></span><br><span class="line">$ script.sh <span class="comment"># Se o script estiver no seu $PATH</span></span><br></pre></td></tr></table></figure>
<p>Eu costumo colocar o shebang e rodar o script com <code>sh script.sh</code> mesmo, porque ficar fazendo <code>chmod +x</code> para cada script que eu crio é muito enjoado. Mas é uma boa prática colocar o shebang, então não deixe de colocar.</p>
<h3 id="Comandos-uteis"><a href="#Comandos-uteis" class="headerlink" title="Comandos úteis"></a>Comandos úteis</h3><p>Alguns comandos você irá usar com mais frequência do que outros. É importante que você saiba que alguns deles existam, para consultá-los quando você precisar. Alguns deles são:</p>
<ul>
<li><code>ls</code>: Lista os arquivos do diretório atual.</li>
<li><code>cd</code>: Troca o diretório atual.</li>
<li><code>rm</code>: Apaga um arquivo ou diretório.</li>
<li><code>mv</code>: Move um arquivo ou diretório.</li>
<li><code>cp</code>: Copia um arquivo ou diretório.</li>
<li><code>echo</code>: Escreve um texto na tela.</li>
<li><code>test</code>: Veremos na parte de condicionais.</li>
<li><code>grep</code>: Imprime linhas que correspondem à um padrão.</li>
<li><code>sed</code>: Modifica e filtra texto.</li>
<li><code>tr</code>: Troca ou deleta caracteres.</li>
<li><code>read</code>: Lê um texto digitado pelo usuário e salva numa variável.</li>
<li><code>pwd</code>: Imprime o diretório local.</li>
<li><code>find</code>: Busca arquivos.</li>
</ul>
<h3 id="Manuais"><a href="#Manuais" class="headerlink" title="Manuais"></a>Manuais</h3><p>Quando você tiver dúvida sobre como um comando funciona, ou qual a sua interface, você deveria consultar sua página no manual: <code>man <comando></code>. Por exemplo, estou com dúvida no <code>ls</code>, então eu digito <code>man ls</code>.</p>
<p><strong>Você deve se acostumar a ler os manuais</strong>. Acostume-se a encontrar os subcomandos existentes e as opções (e.g. <code>--opcao</code>) que você precisa. E busque compreender mais ou menos a seção <code>SYNOPSIS</code> das páginas dos manuais.</p>
<p>E tenha em mente que as páginas dos manuais podem ser diferentes dependendo da shell que você está usando. A maioria dos programas é a mesma coisa, porém alguns comandos como <code>read</code>, por exemplo, podem funcionar um pouco diferente dependendo da Shell. Eu uso o <code>fish</code> diáriamente, e, quando estou fazendo um script, vez ou outra, tenho que entrar no <code>bash</code> só para consultar o manual de algum comando. Isso já me deu dor de cabeça algumas vezes. Se você usa o <code>bash</code>, você não deve ter muitos problemas com isso, mas fica esperto.</p>
<h3 id="Wildcards-Globs"><a href="#Wildcards-Globs" class="headerlink" title="Wildcards (Globs)"></a>Wildcards (Globs)</h3><p><a href="https://en.wikipedia.org/wiki/Glob_%28programming%29" target="_blank" rel="external"><em>Globs</em></a> são um tipo de <a href="https://en.wikipedia.org/wiki/Wildcard_character" target="_blank" rel="external"><em>Wildcard</em></a>, e são usados para selecionar arquivos em sistemas Unix. São caracteres que representam uma sequência genérica de caracteres. <code>?</code> representa qualquer caractere. E <code>*</code>, qualquer quantidade de qualquer caractere.</p>
<p>Vamos supor que você tem um diretório com os seguintes arquivos: <code>script.pl</code>, <code>script.sh</code>, <code>script.pl</code>, <code>script.test.sh</code>, <code>test.c</code> e <code>test.java</code>. Se você entrar nesse diretório e usar o comando <code>rm test.*</code>, você irá remover os arquivos <code>test.c</code> e <code>test.java</code>, mas os outros arquivos ficarão intactos.</p>
<p>Isso funciona por uma expansão que ocorre antes mesmo do programa ser executado. No caso anterior, <code>rm test.*</code> será expandido para <code>rm test.c test.java</code>, e então o programa é invocado com estes dois argumentos.</p>
<p>Outro exemplo. Se usamos o comando <code>mv *.txt textfiles/</code> moveremos todos os arquivos com a extensão <code>.txt</code> para o diretório <code>textfiles/</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">rm script.* <span class="comment"># Apaga arquivos tipo: 'script.py', 'script.sh', 'script.pl', e etc.</span></span><br><span class="line">rm <span class="string">"script.*"</span> <span class="comment"># Globs não funcionam dentro de aspas.</span></span><br><span class="line">rm <span class="variable">$HOME</span>/fotos/viagem/*-2015-01-??.jpg <span class="comment"># Remove as fotos de janeiro de 2015.</span></span><br><span class="line">rm <span class="variable">$HOME</span>/fotos/viagem/*.jpg <span class="comment"># Remove todas as fotos da viagem.</span></span><br></pre></td></tr></table></figure>
<p><em>Globs</em> são muito úteis, e você deveria aprender a usar bem, pelo menos, o <code>*</code>.</p>
<h2 id="Variaveis"><a href="#Variaveis" class="headerlink" title="Variáveis"></a>Variáveis</h2><p>Chega daquelas discussões sobre o que é melhor: tipagem forte, ou tipagem fraca. Ao contrário da maioria das linguagens de programação, em que você tem vários tipos de variáveis (integer, string, boolean, etc), em shell script você tem apenas um tipo de variável… Strings!</p>
<p>Criar uma variável é bem simples:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">variavel=<span class="string">"Conteúdo da variável"</span></span><br></pre></td></tr></table></figure>
<p><strong>Importante:</strong> não coloque espaços ao redor do <code>=</code>; não comece com números; não use hífen <code>-</code>; não use caracteres especiais como <code>ç</code>, <code>á</code>, <code>火災</code> e nem emojis <code>😀</code>, <code>😂</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Não use nomes que nem esses:</span></span><br><span class="line">98bottles=<span class="string">"98"</span> <span class="comment"># Não comece com números.</span></span><br><span class="line">bad-variable=<span class="string">"crap"</span> <span class="comment"># Não use hífen '-'.</span></span><br><span class="line">erro = <span class="string">"erro"</span> <span class="comment"># Não coloque espaços ao redor do '='.</span></span><br><span class="line">maçã=<span class="string">"maca"</span> <span class="comment"># Não use caracteres especiais nos nomes.</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Use nomes que nem esses:</span></span><br><span class="line">bottles_n_98=98 <span class="comment"># As aspas são opcionais quando o conteúdo da variável não contém espaços.</span></span><br><span class="line">good_variable=<span class="string">"(y)"</span> <span class="comment"># Use underline '_' como alternativa para o hífen '-'.</span></span><br><span class="line">CamelCase=<span class="string">"Camelo"</span> <span class="comment"># Mau gosto, porém é permitido.</span></span><br><span class="line">maca=maçã-火災-😀 <span class="comment"># No conteúdo você pode usar caracteres especiais. 👍</span></span><br></pre></td></tr></table></figure>
<p>Agora, na hora de usar as variáveis é que tem uma pegadinha. Você deve usar <code>$</code> para acessar o valor de qualquer variável. Então a variável <code>fruta=maçã</code> deve ser acessada como <code>$fruta</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">texto=<span class="string">"Hello World"</span></span><br><span class="line"><span class="built_in">echo</span> texto <span class="comment"># Pegadinha. Vai imprimir "texto".</span></span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$texto</span> <span class="comment"># Vai imprimir "Hello World".</span></span><br></pre></td></tr></table></figure>
<p>Quando você estiver escrevendo strings, você pode usar <code>'</code> ou <code>"</code>. Usando <code>"</code> o valor das variáveis são colocados no lugar dos seus nomes. Usando <code>'</code> o nome dá variável fica do jeito que está na string. O <code>'</code> ignora a existência de variáveis.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">'$HOME'</span> <span class="comment"># Imprime: $HOME</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"<span class="variable">$HOME</span>"</span> <span class="comment"># Imprime, ex: /home/possatti</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"A home do usuário '<span class="variable">$USER</span>' é '<span class="variable">$HOME</span>'"</span> <span class="comment"># ex: A home do usuário 'possatti' é '/home/possatti'</span></span><br></pre></td></tr></table></figure>
<p>Para ler uma variável do <code>stdin</code> (mais tarde eu explico sobre <em>File Descriptors</em>), ou seja, algum valor que o usuário tenha digitado, use o comando <code>read</code>. Exemplo:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> -n <span class="string">"Digite seu nome: "</span></span><br><span class="line"><span class="built_in">read</span> nome</span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Olá, <span class="variable">$nome</span>!"</span></span><br></pre></td></tr></table></figure>
<p>Além das variáveis que você cria dentro do script, já existem algumas prontas para você usar. Nós chamamos elas de variáveis de ambiente (environment variables). Você pode abrir um terminal, digitar <code>$</code> e apertar tab duas vezes, e uma lista de variáveis vai aparecer para você. Algumas das mais úteis são: <code>$HOME</code>, <code>$HOSTNAME</code>, <code>$LANG</code>, <code>$RANDOM</code>, <code>$PWD</code>, <code>$PATH</code>, <code>$SHELL</code>, <code>$USER</code>, <code>$USERNAME</code>.</p>
<p>Você também pode passar variáveis de ambiente temporárias para um script, invocando ele como <code>VARIAVEL1=whatever VARIAVEL2=whatever ./script.sh</code>.</p>
<p>Também é uma convenção usar nomes de variáveis em letras maiúsculas. E geralmente é uma ótima ideia seguir as convenções. Mas você vai perceber que eu não tô nem aí pra essa convenção especificamente… kkk. Isso porque eu acho que escrever o nome das minhas variáveis em minúsculo diferencia elas melhor das variáveis de ambiente.</p>
<h2 id="Substituicao-de-comandos"><a href="#Substituicao-de-comandos" class="headerlink" title="Substituição de comandos"></a>Substituição de comandos</h2><p>As vezes é útil guardarmos a saída de algum programa. Ao invés de imprimir na tela, gostaríamos de pegar esse valor e, por exemplo, guardar em uma variável. Para isso, usamos <a href="https://en.wikipedia.org/wiki/Command_substitution" target="_blank" rel="external">substituição de comandos</a>: <code>$(prog)</code>, ou <code>`prog`</code>. Até onde eu sei, não há diferença entre as duas formas. Eu, particularmente, prefiro o segundo.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> `<span class="built_in">pwd</span>` <span class="comment"># Imprime o diretório atual</span></span><br><span class="line"><span class="built_in">echo</span> $(<span class="built_in">pwd</span>) <span class="comment"># Imprime o diretório atual</span></span><br><span class="line">arquivos_de_texto=$(ls *.txt)</span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$arquivos_de_texto</span> <span class="comment"># Imprime todos os "txt" do diretório atual</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"2 + 2 = <span class="variable">$(expr 2 + 2)</span>"</span> <span class="comment"># Imprime '2 + 2 = 4'</span></span><br></pre></td></tr></table></figure>
<h2 id="Condicionais"><a href="#Condicionais" class="headerlink" title="Condicionais"></a>Condicionais</h2><p>Esse é o <code>if</code> mais feio que você provavelmente vai escrever na sua vida. Mas vamos nessa.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="built_in">echo</span> -n <span class="string">"Digite sua idade: "</span></span><br><span class="line"><span class="built_in">read</span> idade</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$idade</span> <span class="_">-lt</span> 18 ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é menor de idade."</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é maior de idade."</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure>
<p>Eu avisei.</p>
<p>No script acima, o usuário digita sua idade. Se ele tiver menos que 18 anos, imprimimos que ele é menor de idade. Caso contrário, imprimimos que ele é maior de idade.</p>
<p>Note que os espaços entre <code>[</code> e <code>]</code> são necessários. <strong>Não</strong> use <code>[$idade -lt 18]</code>, use <code>[ $idade -lt 18 ]</code>. Se você não colocar os espaços, você terá um erro.</p>
<p>Agora vamos olhar como esse <code>if</code> funciona de verdade. Na Bourne Shell, quando escrevemos <code>[ $idade -lt 18 ]</code>, isso é a mesma coisa que <code>test $idade -lt 18</code>. Na verdade, verdade verdadeira, ele usa um comando para avaliar a nossa expressão. Os valores <code>$idade</code>, <code>-lt</code> e <code>18</code> estão sendo passados como argumentos para o programa <code>test</code>, e ele vai avaliar a expressão. Se a expressão for verdadeira, <code>test</code> termina a execução com o valor <code>0</code> (<code>exit 0</code>). Se a expressão for falsa, ele termina com um valor diferente (geralmente <code>1</code>).</p>
<p>Agora que você já sabe que o comando <code>test</code> está sendo usado, você já pode consultar o manual para saber que tipos de condições você pode construir: <code>man test</code>. O <code>test</code> pode realizar vários tipos de comparações, aqui estão algumas operações possíveis.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">test</span> 42 <span class="_">-eq</span> 42 <span class="comment"># eq: equal = os inteiros são iguais</span></span><br><span class="line"><span class="built_in">test</span> 3 <span class="_">-gt</span> 2 <span class="comment"># gt: greater-than = maior-quê</span></span><br><span class="line"><span class="built_in">test</span> 3 -ge 2 <span class="comment"># ge: greater-than or equal = maior ou igual</span></span><br><span class="line"><span class="built_in">test</span> 2 <span class="_">-lt</span> 3 <span class="comment"># lt: less-than = menor-quê</span></span><br><span class="line"><span class="built_in">test</span> 2 -le 3 <span class="comment"># le: less-than or equal = menor ou igual</span></span><br><span class="line"><span class="built_in">test</span> 0 <span class="_">-ne</span> 1 <span class="comment"># ne: not-equal = os inteiros não são iguais</span></span><br><span class="line"><span class="built_in">test</span> -n <span class="string">"Texto"</span> <span class="comment"># n: String tem mais que zero caracteres</span></span><br><span class="line"><span class="built_in">test</span> -z <span class="string">""</span> <span class="comment"># z: String tem zero carácteres</span></span><br><span class="line"><span class="built_in">test</span> <span class="string">"Goiaba"</span> == <span class="string">"Goiaba"</span> <span class="comment"># ==: As Strings são iguais</span></span><br><span class="line"><span class="built_in">test</span> <span class="string">"Goiaba"</span> != <span class="string">"Mamão"</span> <span class="comment"># ==: As Strings são diferentes</span></span><br><span class="line"><span class="built_in">test</span> <span class="_">-d</span> <span class="string">"/home"</span> <span class="comment"># Verifica se o diretório existe</span></span><br><span class="line"><span class="built_in">test</span> <span class="_">-f</span> saci-pererê.txt <span class="comment"># f: Arquivo existe</span></span><br></pre></td></tr></table></figure>
<p>Podemos reescrever o condicional do código anterior usando o <code>test</code> explicitamente. Dá na mesma coisa:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> <span class="built_in">test</span> <span class="variable">$idade</span> <span class="_">-lt</span> 18; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é menor de idade."</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é maior de idade."</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure>
<p>Todo comando que é executado retorna algum valor. Se tudo ocorreu bem, retorna <code>0</code>. Se deu algum erro, retorna <code>1</code> ou outro valor. Em shell script, <code>0</code> significa verdadeiro, e os outros valores significam falso. E como eu disse, todo comando retorna um valor para a shell, inclusive o seu script! Você usa <code>exit</code> para especificar que valor deve ser retornado. Se você não especificar, o retorno do último comando do seu script será usado.</p>
<p>E existe uma variável especial, chamada <code>$?</code> que guarda o retorno do último comando executado. Pode ser útil, às vezes.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> rm saci-pererê.txt; <span class="keyword">then</span> <span class="built_in">echo</span> <span class="string">"Saci foi apagado."</span>; <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">test</span> <span class="_">-f</span> saci-pererê.txt <span class="comment"># Testa se o arquivo existe.</span></span><br><span class="line"><span class="keyword">if</span> [ $? <span class="_">-eq</span> 0 ]; <span class="keyword">then</span> <span class="comment"># O valor do comando anterior (test) entra no lugar de '$?'.</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Saci ainda existe!"</span></span><br><span class="line"> <span class="built_in">exit</span> 1 <span class="comment"># Saímos com erro, porque o Saci não devia mais existir.</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">exit</span> 0 <span class="comment"># Saci deixou de existir. Sucesso!</span></span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure>
<h2 id="Switch-case"><a href="#Switch-case" class="headerlink" title="Switch case"></a>Switch case</h2><p>Outra estrutura com uma sintaxe curiosa. Se você achava o <code>if</code> estranho, é melhor se sentar. Surpreendentemente ele é mais útil do que parece, pela forma como ele trata as strings. Você pode usar wildcards (<code>*</code> e <code>?</code>) para enriquecer as expressões usadas no switch.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="built_in">echo</span> -n <span class="string">"Em que planeta você mora? "</span></span><br><span class="line"><span class="built_in">read</span> planeta</span><br><span class="line"></span><br><span class="line"><span class="keyword">case</span> <span class="variable">$planeta</span> <span class="keyword">in</span></span><br><span class="line"> <span class="string">"terra"</span>)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é terráqueo."</span></span><br><span class="line"> ;;</span><br><span class="line"></span><br><span class="line"> <span class="string">"marte"</span>)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é marciano."</span></span><br><span class="line"> ;;</span><br><span class="line"> *)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Você é um lixo das galáxias! Sorry..."</span></span><br><span class="line"> ;;</span><br><span class="line"><span class="keyword">esac</span> <span class="comment"># "case" ao contrário para fechar o switch</span></span><br></pre></td></tr></table></figure>
<p>Repare que você fecha o <code>case</code> usando <code>esac</code> (<code>case</code> ao contrário). E não me pergunte porquê você tem que colocar <code>;;</code> no final de cada caso! Deixo isso como um dever de casa para você. Boa sorte.</p>
<h2 id="Loops"><a href="#Loops" class="headerlink" title="Loops"></a>Loops</h2><p>Temos duas opções de loop aqui: <code>while</code> e <code>for</code>. Cada um é útil em uma situação específica.</p>
<h3 id="For"><a href="#For" class="headerlink" title="For"></a>For</h3><p>Na sua forma mais simples, você descrimina uma série de valores para o <code>for</code>, e a iteração acontecerá em cima desses valores. Veja o exemplo abaixo:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="comment"># O script irá imprimir 'goiaba', 'abacaxi', e 'banana'</span></span><br><span class="line"><span class="comment"># cada um em uma linha separada.</span></span><br><span class="line"><span class="keyword">for</span> fruta <span class="keyword">in</span> goiaba abacaxi banana; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="variable">$fruta</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>Abaixo está um exemplo levemente mais útil. O script apagará todos os arquivos do diretório atual, exceto o arquivo <code>critico.txt</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="comment"># Pega todos os "txt" do diretório local.</span></span><br><span class="line">arquivos_txt=`ls *.txt`</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> arquivo <span class="keyword">in</span> <span class="variable">$arquivos_txt</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="keyword">if</span> [ <span class="variable">$arquivo</span> == <span class="string">"critico.txt"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">continue</span> <span class="comment"># Pula 'critico.txt' para que ele não seja apagado</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> rm <span class="variable">$arquivo</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>A variável <code>$arquivos_txt</code> é uma string que contém o nome de todos os arquivos <code>.txt</code> do diretório atual, separados por espaço. O <code>for</code> irá quebrar essa string em múltiplos pedaços, separando pelos espaços e pelas quebras de linha (<code>\n</code>). Esses múltiplos pedaços serão passados para a variável <code>$arquivo</code>, um de cada vez.</p>
<p>Você também pode usar as palavras chaves <code>continue</code> para pular uma iteração e continuar do começo, e <code>break</code> para sair do loop.</p>
<p>Quando você desejar iterar sob uma sequência de números, você pode usar o comando <code>seq</code>. Exemplo: <code>seq 3</code> irá imprimir <code>1 2 3</code> (separados por <code>\n</code>, na verdade) e <code>seq 0 3</code> irá imprimir <code>0 1 2 3</code>. No exemplo abaixo, nós criamos uma sequência de 0 à 10, e elevamos cada um dos números ao quadrado, e imprimimos.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="keyword">for</span> i <span class="keyword">in</span> $(seq 0 10); <span class="keyword">do</span></span><br><span class="line"> i_quadrado=$(expr <span class="variable">$i</span> <span class="string">'*'</span> <span class="variable">$i</span>)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$i</span> ao quadrado é igual a: <span class="variable">$i_quadrado</span>"</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<h3 id="While"><a href="#While" class="headerlink" title="While"></a>While</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="comment"># Observação: Fazer um loop para vigiar se um arquivo foi criado</span></span><br><span class="line"><span class="comment"># é uma das piores coisas que você pode fazer durante sua existência</span></span><br><span class="line"><span class="comment"># na terra. Isso vai usar todo o seu processador. Não faça isso! É</span></span><br><span class="line"><span class="comment"># só um exemplo.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> [ ! <span class="_">-f</span> saci-pererê.txt ]; <span class="keyword">do</span> <span class="comment"># Enquanto o arquivo *não* existe</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">'Vigiando o Saci ser criado.'</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Alguém criou o Saci!! Apaga o Saci!"</span></span><br><span class="line">rm saci-pererê.txt</span><br></pre></td></tr></table></figure>
<p>No exemplo, nós constantemente verificamos se o arquivo <code>saci-pererê.txt</code> existe. Enquanto o arquivo não existir, nós continuamos no loop imprimindo uma mensagem. Assim que o arquivo é criado, o loop termina, e nós apagamos o arquivo do Saci.</p>
<p>Se você quiser trollar um amigo que usa Ubuntu, execute o script seguinte no computador dele. Coloque o arquivo em sua <code>$HOME</code> com o nome de <code>dull-boy.sh</code> (o nome é importante).</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="comment"># Número de ciclos do while para criar uma nova instância</span></span><br><span class="line"><span class="comment"># do gnome-terminal.</span></span><br><span class="line">ciclos_para_nova_instancia=1000</span><br><span class="line"></span><br><span class="line">ciclos=0</span><br><span class="line"><span class="keyword">while</span> <span class="literal">true</span></span><br><span class="line"><span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"All work and no play makes Jack a dull boy"</span></span><br><span class="line"> <span class="comment"># Incrementa o número de ciclos.</span></span><br><span class="line"> ciclos=`expr <span class="variable">$ciclos</span> + 1`</span><br><span class="line"> <span class="comment"># Verifica se chegou o momento de criar uma nova instância.</span></span><br><span class="line"> <span class="keyword">if</span> [ <span class="string">"<span class="variable">$ciclos</span>"</span> <span class="_">-eq</span> <span class="string">"<span class="variable">$ciclos_para_nova_instancia</span>"</span> ]</span><br><span class="line"> <span class="keyword">then</span></span><br><span class="line"> <span class="comment"># Cria uma nova instância do gnome-terminal, executando o mesmo script.</span></span><br><span class="line"> gnome-terminal -x sh dull-boy.sh</span><br><span class="line"> <span class="comment"># Reinicia a contagem dos ciclos.</span></span><br><span class="line"> ciclos=0</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>O script irá imprimir <code>"All work and no play makes Jack a dull boy"</code> indeterminadamente. E a cada mil iterações, irá instanciar um novo terminal executando o mesmo script. Então seguindo uma curva exponencial, em pouco tempo você terá dezenas ou centenas de terminais na tela, todos imprimindo <code>"All work and no play makes Jack a dull boy"</code> ininterruptamente.</p>
<p>Você pode tentar parar cada script com <code>Ctrl+C</code>. Porém chega uma hora que a única solução razoável é esperar que o sistema operacional congele os processos, ou, mais fácil, reiniciar o computador.</p>
<p>Se você quiser trollar seu amigo em dobro, coloque uma linha <code>cd $HOME; sh dull-boy.sh</code> no final do arquivo <code>.bashrc</code> (se ele usa o Bash), assim o script irá executar toda vez que ele abrir o terminal. Mas cuidado, pois você pode não ter um amigo depois disso.</p>
<h2 id="Argumentos"><a href="#Argumentos" class="headerlink" title="Argumentos"></a>Argumentos</h2><p>A maioria dos programas de linha de comando recebem e processam argumentos que são passados pelo usuário que está invocando o programa.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ comando arg1 arg2 arg3 arg4</span><br></pre></td></tr></table></figure>
<p>E para acessarmos os argumentos, usamos as variáveis <code>$1</code>, <code>$2</code>, <code>$3</code> e etc para acessarmos o primeiro argumento, o segundo argumento e daí em diante. <code>$0</code> é o nome do seu script (até que faz sentido, né?). E <code>$@</code> representa todos os argumentos juntos e em sequência (sem o <code>$0</code>). E <code>$#</code> é o número de argumentos recebidos (também sem o <code>$0</code>).</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"\$0: <span class="variable">$0</span>"</span> <span class="comment"># Imprime o nome do script.</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"\$@: <span class="variable">$@</span>"</span> <span class="comment"># Imprime todos os argumentos.</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"\$#: <span class="variable">$#</span>"</span> <span class="comment"># Imprime o número de argumentos.</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"\$1 \$2 \$3: <span class="variable">$1</span> <span class="variable">$2</span> <span class="variable">$3</span>"</span> <span class="comment"># Imprime os primeiros três argumentos.</span></span><br></pre></td></tr></table></figure>
<p>Se o seu script tiver recebido apenas dois argumentos e você tentar acessar, digamos, o argumento <code>$3</code>, o <code>$3</code> será substituído por uma string vazia. Para evitar isso, você pode testar se <code>$3</code> não é uma string vazia: <code>test -n "$3"</code> (as aspas são importantes nesse caso).</p>
<p>Quando um argumento tem a forma <code>-e</code> ou <code>--exemplo</code>, ele é chamado de uma opção, e geralmente é… opcional na chamada de um programa. Você usou opções este tempo inteiro (<code>echo -n</code>, <code>rm -rf</code>, etc), deve saber como elas funcionam. Mas só para o caso de você não saber, vou explicar um pouquinho.</p>
<p>Algumas opções são chamadas de forma isolada, como <code>--quiet</code>, e <code>--help</code>, e outras devem ser acompanhadas de um valor como: <code>--garrafas=12</code>, <code>--garrafas 12</code>, <code>-g12</code>. Ou: <code>--arquivo="file.txt"</code>, <code>--arquivo "file.txt"</code>. As opções podem ser usadas, não importa a ordem: <code>cmd --input "i.txt" --output "o.txt"</code> deveria ser a mesma coisa que <code>cmd --output "o.txt" --input "i.txt"</code>. E as opções geralmente são misturadas com argumentos: <code>echo "hello" -n</code> (<code>n</code> é uma opção e <code>"hello"</code>, um argumento). E muitas opções que são escritas por extenso também tem uma forma abreviada, como: <code>--help</code> é equivalente à <code>-h</code>; e <code>--quiet</code> é equivalente à <code>-q</code>. Quando você usa a forma abreviada, muitas vezes você também pode aglutinar as formas abreviadas, por exemplo <code>rm -rf</code> é equivalente à <code>rm -r -f</code>.</p>
<p>É claro que nem todos os programas vão seguir essas regras para suas interfaces, mas essas são regras que você vai observar na maioria dos programas de linha de comando. Existem exceções, como exemplo, o programa <code>java</code> não têm opções abreviadas e as opções extensas usam um único hífen, tipo: <code>java -version</code> ou <code>java -help</code>. (Para o caso de dúvida, programas feitos em Java podem ter qualquer interface que eles quiserem. Eu só quis dizer que o executável <code>java</code> funciona dessa forma.)</p>
<p>E repare que apesar de <code>--arquivo "file.txt"</code> ser uma única opção, na shell eles são visto como dois argumentos separados. Shell script não diferencia argumentos de opções por você. Para o shell script, tudo é argumento.</p>
<p>Se você quiser iterar sobre todos os argumentos, você pode usar um <code>for</code> para isso:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="keyword">for</span> arg <span class="keyword">in</span> <span class="variable">$@</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Argumento <span class="variable">$arg</span>."</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>Outra opção semelhante é usar o comando <code>shift</code> juntamente com um <code>while</code>. Quando você usa <code>shift</code>, o <code>$2</code> será colocado no lugar do <code>$1</code>; o <code>$3</code> no lugar do <code>$2</code>; e assim em diante. Dessa forma você pode ler o primeiro argumento através do <code>$1</code>; fazer um <code>shift</code>, ler o segundo argumento através do <code>$1</code>; <code>shift</code>, ler terceiro argumento através do <code>$1</code> também; e etc.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="comment"># Irá imprimir "arg1", "arg2", "arg3", etc.</span></span><br><span class="line"><span class="keyword">while</span> [ -n <span class="string">"<span class="variable">$1</span>"</span> ]; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Argumento <span class="variable">$1</span>."</span></span><br><span class="line"> <span class="built_in">shift</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>Se você for criar um script que tenha uma interface extensa e complexa, e que precisa diferenciar e tratar argumentos e opções, você terá que usar altos recursos <em>imaginísticos</em> para alcançar seus objetivos. Há algum tempo atrás eu tive que fazer isso, e tive sucesso usando um <code>while</code> com um <code>case</code> e o comando <code>shift</code>. Se você precisar de inspiração, consulte o meu repositório <a href="https://github.com/possatti/pokemonsay/blob/master/pokemonsay.sh" target="_blank" rel="external">“pokemonsay”</a> no Github.</p>
<h2 id="Pipe-e-redirecao"><a href="#Pipe-e-redirecao" class="headerlink" title="Pipe e redireção"></a>Pipe e redireção</h2><p>Essa é provavelmente a coisa mais interessante que você pode fazer em shell script. É usando <em>Pipes</em> (literalmente, canos, ou tubos) e redireção que você vai conseguir libertar os verdadeiros poderes do shell script.</p>
<p>Antes de falar sobre isso, eu tenho que explicar uma coisa mais básica: <em>File Descriptors</em>. No mundo do Unix e Linux existe o que nós chamamos de <em>“file descriptor”</em>. Qualquer programa têm três <em>file descriptors</em>: Standard Input, Standard Output, e Standard Error. Comumente abreviados: <code>stdin</code>, <code>stdout</code> e <code>stderr</code>. O programa irá ler dados do <code>stdin</code>, irá escrever em <code>stdout</code>, e irá escrever os erros para <code>stderr</code>. Muitas vezes, o texto vindo de <code>stdin</code> será o texto digitado pelo usuário no teclado. Mas muitas outras vezes, esse texto será recebido de forma programática.</p>
<p>Quando usamos pipe <code>|</code>, nós estamos conectando o <code>stdout</code> do comando à esquerda, com o <code>stdin</code> do comando à direita. Também é possível fazer vários pipes em sequência. Você deve imaginar que o texto está fluindo da esquerda para a direita, e que cada comando está modificando o texto, ou agindo de alguma forma sobre ele. Vamos à um exemplo simples:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Imprime "laranja_123" (minúsculo)</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"LARANJA_123"</span> | tr <span class="string">'[:upper:]'</span> <span class="string">'[:lower:]'</span></span><br></pre></td></tr></table></figure>
<p>O <code>tr</code> é um programa que troca alguns caracteres por outros (<code>man tr</code>). Perceba que o <code>echo</code> escreveu o texto em seu <code>stdout</code> (normalmente seria impresso, mas não foi devido ao pipe), e seu <code>stdout</code> foi redirecionado para o <code>stdin</code> de <code>tr</code>. E o <code>tr</code>, após manipular o texto (substituir maiúsculas por minúsculas), escreveu o resultado em seu <code>stdout</code>, que por sua vez foi impresso na tela.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Imprime "laranja"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"LARANJA_123"</span> | tr <span class="string">'[:upper:]'</span> <span class="string">'[:lower:]'</span> | tr <span class="_">-d</span> <span class="string">'[_0-9]'</span></span><br></pre></td></tr></table></figure>
<p>Mais um pipe agora. Dessa vez, o <code>stdout</code> do primeiro <code>tr</code> não é impresso, mas é redirecionado para o <code>stdin</code> do segundo <code>tr</code>. O segundo <code>tr</code> irá ler o texto de seu <code>stdin</code>, modificá-lo (remover os números e underline <code>_</code>), e escrever em seu <code>stdout</code>. Como não há mais nenhuma redireção, seu <code>stdout</code> será impresso.</p>
<p>Também podemos fazer redireções usando arquivos. <code>></code> é usado para redirecionar o <code>stdout</code> para um arquivo, porém apaga o conteúdo do arquivo se ele já existir. <code>>></code> faz o mesmo que <code>></code>, porém não apaga o conteúdo original do arquivo. Ao final do script abaixo, teremos um arquivo com três frutas: Caju, Mamão e Pêra.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Escreve "Banana" no arquivo "frutas.txt".</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Banana"</span> > frutas.txt</span><br><span class="line"><span class="comment"># Apaga o conteúdo do arquivo inteiro, e depois escreve "Caju" nele.</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Caju"</span> > frutas.txt</span><br><span class="line"><span class="comment"># Escreve "Mamão" no final do arquivo, sem apagar seu conteúdo.</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Mamão"</span> >> frutas.txt</span><br><span class="line"><span class="comment"># Escreve "Pêra_123" no final do arquivo, sem apagar seu conteúdo.</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Pêra_123"</span> >> frutas.txt</span><br></pre></td></tr></table></figure>
<p>Equivalente ao <code>></code> temos o <code><</code> que faz exatamente o contrário. Ele serve para “puxarmos” o texto de um arquivo e fornecer como entrada para o <code>stdin</code> de um programa. Exemplo:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Transforma o texto de 'frutas.txt' para maiúsculas.</span></span><br><span class="line">tr <span class="string">'[:lower:]'</span> <span class="string">'[:upper:]'</span> < frutas.txt</span><br></pre></td></tr></table></figure>
<p>O texto contido em <code>frutas.txt</code> será direcionado para o <code>stdin</code> de <code>tr</code>, que irá modificar o texto e imprimir na tela.</p>
<p>Também é comum usarmos <code><</code>, <code>></code> e <code>|</code> tudo junto. É um pouco difícil de se acostumar com a leitura. Mas é algo comum e útil. Veja o exemplo abaixo.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Transforma o texto de 'frutas.txt' para maiúsculas, remove números e '_'</span></span><br><span class="line"><span class="comment"># e grava em 'FRUTAS.TXT'.</span></span><br><span class="line"><span class="comment"># Perceba que nada é impresso. Pois tudo é gravado em 'FRUTAS.TXT'.</span></span><br><span class="line">tr <span class="string">'[:lower:]'</span> <span class="string">'[:upper:]'</span> < frutas.txt | tr <span class="_">-d</span> <span class="string">'[_0-9]'</span> > FRUTAS.TXT</span><br></pre></td></tr></table></figure>
<p>Pêra! (huehue) Se existe <code>></code> e <code>>></code>, deve existir também <code><<</code>, já que existe <code><</code>. Sim, senhor. E o nome disso é <a href="https://en.wikipedia.org/wiki/Here_document" target="_blank" rel="external">“Here Document”</a>. Ao invés de ler de um arquivo (como <code><</code>) o texto será lido do próprio script.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">tr <span class="string">'[:lower:]áãçó'</span> <span class="string">'[:upper:]ÁÃÇÓ'</span> << EOF</span><br><span class="line">O empenho em analisar o aumento <span class="keyword">do</span> diálogo entre os diferentes</span><br><span class="line">setores produtivos estimula a padronização dos modos de operação</span><br><span class="line">convencionais.</span><br><span class="line">Desta maneira, o julgamento imparcial das eventualidades cumpre</span><br><span class="line">um papel essencial na formulação <span class="keyword">do</span> impacto na agilidade decisória.</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure>
<p>Perceba que depois do <code><<</code> temos um token (<code>EOF</code>) que abre o texto do <a href="http://www.lerolero.com/" target="_blank" rel="external">lerolero.com</a>, e em seguida o <strong>mesmo token</strong> deverá ser repetido em sua própria linha, para fechar o texto. O texto que está entre os dois <code>EOF</code> (<em>end of file</em>, fim de arquivo), será usado como entrada de dados para o <code>tr</code>, que por usa vez imprimirá o texto inteiro em letras maiúsculas. É comum usarmos a sigla <code>EOF</code> como token, mas pode ser qualquer palavra, como <code>LEROLERO</code>, ou <code>HELLO_WORLD!</code>.</p>
<p>Agora um pequeno exercício mental. Tente entender que parte de texto está servindo de entrada para qual comando. Boa sorte.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line">sh << MIND</span><br><span class="line">sh << BLOWING</span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Mind blowing."</span></span><br><span class="line">BLOWING</span><br><span class="line">MIND</span><br></pre></td></tr></table></figure>
<p>Cada <em>file descriptor</em> tem um número associado: <code>stdin</code>, <code>0</code>; <code>stdout</code>, <code>1</code>; e <code>stderr</code>, <code>2</code>. É comum redirecionarmos o <code>stderr</code> de um programa para o <code>stdout</code> do mesmo programa. Fazemos isso usando <code>2>&1</code>. Isso é muito útil quando temos um programa que escreve coisas importantes para <code>stderr</code>, porém nós queremos gravar em um arquivo, por exemplo. Para isso fazemos <code>prog 2>&1 > meu.log</code>. Ou ainda podemos gravar o <code>stdout</code> e o <code>stderr</code> em diferentes arquivos: <code>prog 1> meu.log 2> erros.log</code>.</p>
<p>E se quisermos direcionar o <code>stdout</code> para <code>stderr</code>, usamos <code>1>&2</code>. Você pode usar isso para escrever em <code>stderr</code> no seu script através de <code>echo 1>&2</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"Hello"</span> <span class="comment"># Imprime através do `stdout`</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"World"</span> 1>&2 <span class="comment"># Imprime na tela, porém através do `stderr`</span></span><br></pre></td></tr></table></figure>
<p>Redireções também funcionam com estruturas como <code>for</code> e <code>while</code>. Quando você chega nesse nível, as coisas podem ficar extremamente confusas. O exemplo abaixo, lê as linhas de um arquivo <code>lower.txt</code>, colocando cada uma delas na variável <code>$linha</code>, que é “<code>echo</code>ada” para <code>tr</code>, que transforma tudo em maiúsculas. Porém o <code>stdout</code> de <code>tr</code> vai para um segundo <code>tr</code> que apaga as vogais do texto. E em seguida, o resultado é escrito em <code>UPPER.txt</code>. Loucura.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="keyword">while</span> <span class="built_in">read</span> linha; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="variable">$linha</span> | tr <span class="string">'[:lower:]'</span> <span class="string">'[:upper:]'</span></span><br><span class="line"><span class="keyword">done</span> < lower.txt | tr <span class="_">-d</span> <span class="string">'aeiou'</span> > UPPER.txt</span><br></pre></td></tr></table></figure>
<p>Era possível escrever o script acima de forma mais simples. Mas eu quis fazer assim, para você exercitar seu poderoso cérebro.</p>
<h2 id="Funcoes"><a href="#Funcoes" class="headerlink" title="Funções"></a>Funções</h2><p>Funções funcionam como mini-scripts contidos no seu script. Elas são declaradas como <code>foo() { ... }</code> e são invocadas como qualquer outro comando: <code>foo arg1 arg2 arg3 ...</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span><br><span class="line"></span></span><br><span class="line"><span class="function"><span class="title">somar</span></span>() {</span><br><span class="line"> <span class="comment"># Soma os dois argumentos recebidos *pela função*.</span></span><br><span class="line"> expr <span class="variable">$1</span> <span class="string">'+'</span> <span class="variable">$2</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># Processa todos os argumentos recebidos pelo script</span></span><br><span class="line"><span class="comment"># somando todos eles.</span></span><br><span class="line">resultado=0</span><br><span class="line"><span class="keyword">while</span> [ -n <span class="string">"<span class="variable">$1</span>"</span> ]; <span class="keyword">do</span></span><br><span class="line"> <span class="comment"># Soma o argumento com o resultado atual.</span></span><br><span class="line"> resultado=`somar <span class="variable">$resultado</span> <span class="variable">$1</span>`</span><br><span class="line"> <span class="comment"># Coloca o $2 no lugar do $1; o $3 no lugar do $2; etc.</span></span><br><span class="line"> <span class="built_in">shift</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"Soma total: <span class="variable">$resultado</span>"</span></span><br></pre></td></tr></table></figure>
<p>Perceba que dentro da função <code>$1</code> e <code>$2</code> são argumentos recebidos <strong>pela função</strong>, e não pelo script. Do lado de fora da função, nós estamos usando o <code>$1</code> que é o primeiro argumento do nosso script. Veja que as duas coisas não se misturam.</p>
<p><strong>Cuidado:</strong> as funções podem alterar variáveis do escopo global:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">troll</span></span>() {</span><br><span class="line"> x=2</span><br><span class="line">}</span><br><span class="line">x=1</span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$x</span> <span class="comment"># Imprime '1'</span></span><br><span class="line">troll <span class="comment"># Muda o valor de 'x'</span></span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$x</span> <span class="comment"># Imprime '2'</span></span><br></pre></td></tr></table></figure>
<p>Eu acho que isso é o que tem de mais importante para falar sobre as funções em shell script. Acho que você deve saber o que fazer a partir daqui. Mas me sinto culpado de não colocar um exemplo um pouco mais complexo. Então abaixo está uma função que calcula o fatorial de um número…</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="title">fatorial</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> [ <span class="string">"<span class="variable">$1</span>"</span> <span class="_">-gt</span> <span class="string">"1"</span> ]; <span class="keyword">then</span></span><br><span class="line"> i=`expr <span class="variable">$1</span> - 1`</span><br><span class="line"> j=`fatorial <span class="variable">$i</span>`</span><br><span class="line"> k=`expr <span class="variable">$1</span> \* <span class="variable">$j</span>`</span><br><span class="line"> <span class="built_in">echo</span> <span class="variable">$k</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> 1</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># Calcula os 5 primeiros fatoriais.</span></span><br><span class="line"><span class="keyword">for</span> n <span class="keyword">in</span> `seq 5`; <span class="keyword">do</span></span><br><span class="line"> fatorial <span class="variable">$n</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<h2 id="Matematica"><a href="#Matematica" class="headerlink" title="Matemática"></a>Matemática</h2><p>De vez em quando precisamos fazer uma conta ou outra em shell script. A forma como fazemos isso é usando qualquer comando que faça contas. Alguns dos mais úteis são <code>expr</code> e <code>bc</code>.</p>
<p>O mais básico é o <code>expr</code>. Ele serve para fazer contas simples, mas deixa a desejar para contas mais complexas e de número flutuante. E ele é um pouco chato quanto aos espaços. Você precisa separar cada um dos números e operadores, pois eles devem ser recebidos como diferentes argumentos. E você precisa ter cuidado com o <code>*</code> de multiplicação, para que ele não seja interpretado como um wildcard antes mesmo de ser recebido pelo <code>expr</code>, então use <code>\*</code> ou <code>'*'</code>. O mesmo vale para os parênteses, use <code>\( ... \)</code>, ou <code>'(' ... ')'</code></p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">expr 2 + 2 <span class="comment"># "4"</span></span><br><span class="line">expr 2+2 <span class="comment"># "2+2" -- lol</span></span><br><span class="line">expr 2+2 + 2 <span class="comment"># "expr: non-integer argument"</span></span><br><span class="line">expr 2 <span class="string">'*'</span> 3 <span class="comment"># "6"</span></span><br><span class="line">expr 8 \* 0.5 <span class="comment"># "expr: non-integer argument"</span></span><br><span class="line">expr 8 / 4 <span class="comment"># "2"</span></span><br><span class="line">expr 8 / 5 <span class="comment"># "1" -- A divisão é inteira</span></span><br><span class="line">expr \( 3 + 7 \) / \( 1 + 1 \) <span class="comment"># "5"</span></span><br></pre></td></tr></table></figure>
<p>Como você pode ver, <code>expr</code> apenas gosta de números inteiros. Além disso, expressões mais complexas ficam extremamente longas, já que você tem que colocar espaços ao redor de tudo.</p>
<p>Para contas um pouco mais complexas, ou quando você quiser usar números decimais, recomendo usar o <code>bc</code>. Porém este programa possui outro inconveniente: você tem que passar as contas para ele por redirecionamento, pois ele não processa contas pelos argumentos. E para contas com muitas casas decimais, use <code>bc -l</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"2 + 2"</span> | bc <span class="comment"># "4"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"2+2 + 2"</span> | bc <span class="comment"># "6"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"2*3"</span> | bc <span class="comment"># "6"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"8 * 0.5"</span> | bc <span class="comment"># "4.0"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"8 / 4"</span> | bc <span class="comment"># "2"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"8 / 5"</span> | bc <span class="comment"># "1"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"8 / 5"</span> | bc <span class="_">-l</span> <span class="comment"># "1.60000000000000000000"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"(3 + 7) /2"</span> | bc <span class="comment"># "5"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"2.22 / 1.22 * 0.75"</span> | bc <span class="comment"># ".75" -- What???</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"2.22 / 1.22 * 0.75"</span> | bc <span class="_">-l</span> <span class="comment"># "1.36475409836065573770" -- Hmmmm</span></span><br></pre></td></tr></table></figure>
<p>Eu nunca usei muito o <code>bc</code>, mas parece que ele é capaz de fazer <a href="https://en.wikipedia.org/wiki/Bc_(programming_language)#GNU_bc" target="_blank" rel="external">bem mais</a>. Se você precisar de expressões matemáticas complexas, dê uma olhada na sua documentação com carinho.</p>
<h2 id="Manipulacao-de-texto"><a href="#Manipulacao-de-texto" class="headerlink" title="Manipulação de texto"></a>Manipulação de texto</h2><p>Umas das coisas mais comuns que você vai fazer em shell script é manipular texto. Por isso é bom que você saiba fazer isso bem. Minha sugestão é que você aprenda bem, um dos seguintes programas: <code>sed</code>, <code>awk</code> ou <code>perl</code>. Eu costumo usar o <code>sed</code>. Porém, explicar como ele funciona é um tutorial à parte. Mas veja algumas coisas básica que você pode fazer com o <code>sed</code>.</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Imprime todo o texto recebido, porém substituindo "banana" por "maçã"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"banana-banana"</span> | sed <span class="string">'s/banana/maçã/g'</span> <span class="comment"># "maçã-maçã"</span></span><br><span class="line"><span class="comment"># Imprime apenas as linhas que começam com "Erro" ou "erro"</span></span><br><span class="line"><span class="built_in">echo</span> <span class="_">-e</span> <span class="string">"Uva\nErro 1\nPêra\nerro2-critico"</span> | sed -nr <span class="string">'/^[Ee]rro/p'</span> <span class="comment"># "Erro 1\nerro2-critico"</span></span><br><span class="line"><span class="comment"># Formata um número de telefone</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">'27988882222'</span> | sed -r <span class="string">'s/(.{2})(.{1})(.{4})(.{4})/(\1) \2 \3-\4/'</span> <span class="comment"># "(27) 9 8888-2222"</span></span><br><span class="line"><span class="comment"># Pega apenas o nome do arquivo</span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"fotos/viagem/familia.jpg"</span> | sed -r <span class="string">'s;.*/([a-Z]+)\..+;\1;'</span> <span class="comment"># "familia"</span></span><br></pre></td></tr></table></figure>
<p>Infelizmente não tem como eu explicar aqui com detalhes como funciona o <code>sed</code>. Mas, pelo menos, o primeiro exemplo você deve ter entendido. Eu, pessoalmente, aprendi o que sei de <code>sed</code> (30% do total, talvez) usando uma <a href="http://www.grymoire.com/Unix/Sed.html" target="_blank" rel="external">página na internet que parecia ter sido feita no período jurássico</a>. Sinta-se livre para buscar qualquer fonte que possa te ajudar.</p>
<h2 id="Conclusao"><a href="#Conclusao" class="headerlink" title="Conclusão"></a>Conclusão</h2><p>Essa é a despedida. Depois de tudo isso, eu agora espero que você consiga usar shell script para resolver seus problemas. Se ficou faltando alguma coisa, ou não deu para entender alguma parte, pode postar o seu feedback aqui nos comentários.</p>
<p>É isso aí. Abraço.</p>
Neste post eu explico sobre várias estruturas usadas em shell script como: loops, condicionais, pipes, redireção, globs, substituição de comandos e mais.
ZettaJShttp://possatti.com.br/zettajs/2015-03-31T04:11:36.000Z2016-06-24T22:25:13.011Z<p><img src="/images/zetta-logo.svg" alt=""></p>
<p>Recentemente fiz um trabalho, na faculdade, sobre Internet das Coisas. Para esse trabalho eu tive de escrever um documento explicando sobre o assunto, e também o Zetta, que é uma plataforma para a Internet das Coisas. Além de desenvolver uma pequena aplicação que ilustrasse o tema. Então resolvi aproveitar para escrever um post sobre isso.</p>
<p>A maior parte do que eu escrevi aqui, já era parte do meu trabalho. Mas eu aperfeiçoei alguns trechos para que algumas coisas ficassem mais claras, e o texto ficasse mais fácil de acompanhar.</p>
<p>Eu irei começar falando sobre Internet das Coisas, de forma geral. E em seguida vou apresentar o Zetta, explicando para que serve e quais os seus pontos fortes e fracos. E no final, demonstrarei como colocar em execução uma aplicação do Zetta que eu desenvolvi.</p>
<h2 id="Introducao-a-Internet-das-Coisas"><a href="#Introducao-a-Internet-das-Coisas" class="headerlink" title="Introdução a Internet das Coisas"></a>Introdução a Internet das Coisas</h2><p>Um conceito que tem ganhado popularidade mais recentemente é o de <a href="http://pt.wikipedia.org/wiki/Internet_das_Coisas" target="_blank" rel="external">Internet das Coisas</a> (IoT, da sigla em inglês para “Internet of Things”). Esse conceito diz respeitos a objetos embarcados com dispositivos eletrônicos que podem se conectar através de uma rede e trocar informações entre si.</p>
<p>Em Internet das Coisas, as “coisas” podem ser inúmeros tipos de dispositivos. Como equipamentos para monitoramento de batimentos cardíacos, luminosidade, velocidade, controladores, luzes, motores, veículos, e muitas outras coisas. Esses dispositivos tem a capacidade de coletar informações úteis e deixá-las fluir entre os outros dispositivos conectados, de forma autônoma. Tudo isso ficará mais claro ao executar a aplicação que desenvolvi.</p>
<p>Para a aplicação do conceito de IoT, existem muitas plataformas e ferramentas. Como, por exemplo: Carriots, Xively, ZettaJS, ThingSpeak, Zatar e muitas outras. Mas aqui eu irei tratar apenas do Zetta.</p>
<h2 id="Sobre-o-Zetta"><a href="#Sobre-o-Zetta" class="headerlink" title="Sobre o Zetta"></a>Sobre o Zetta</h2><p>O Zetta é uma plataforma Open Source construída em cima do <a href="https://nodejs.org/" target="_blank" rel="external">Node.js</a> para criar servidores para aplicação de Internet das Coisas. Tendo seu primeiro commit feito no dia 18 de abril de 2014 em seu <a href="https://github.com/zettajs/zetta/" target="_blank" rel="external">repositório oficial</a>, o Zetta é uma plataforma relativamente nova, mas em constante desenvolvimento. Em sua <a href="http://www.zettajs.org/" target="_blank" rel="external">página principal</a>, o Zetta declara utilizar uma API <a href="http://pt.wikipedia.org/wiki/REST" target="_blank" rel="external">RESTful</a>, <a href="http://pt.wikipedia.org/wiki/WebSocket" target="_blank" rel="external">WebSockets</a> e <a href="http://en.wikipedia.org/wiki/Reactive_programming" target="_blank" rel="external">Programação Reativa</a> para conectar diversos dispositivos e proporcionar a criação de aplicações com intensa manipulação de dados, em tempo real.</p>
<p>Como eu disse, o Zetta funciona em cima do Node.js (ou apenas Node), que é uma plataforma construída usando o V8, o Runtime de JavaScript do Google Chrome. O Node é útil para construir servidores web de forma rápida e fácil. E a linguagem JavaScript é utilizada para a programação.</p>
<p>É possível executar um servidor Zetta em uma variedade de dispositivos, desde um PC qualquer, até um Arduíno, ou um Raspberry Pi. Assim o servidor pode se comunicar com diversos equipamentos conectados, como LEDs, sensores, telas e basicamente tudo com o qual o seu dispositivo puder se comunicar.</p>
<p>Os desenvolvedores do Zetta, desenvolveram também o Zetta Browser. Que é uma aplicação web que pode ser utilizada para navegar através da API do Zetta. Assim, é possível apontá-lo para o endereço de um servidor Zetta e visualizar em tempo real todos os dados sendo coletados por aquele servidor. Bem como interagir com os dispositivos conectados a ele. Isso tudo em uma interface agradável e intuitiva. Contudo, o browser é um pouco instável, e as vezes apresenta algumas falhas. Mas, no geral, é uma ferramenta muito útil.</p>
<p>O Zetta objetiva proporcionar uma maneira fácil e rápida de projetar aplicações para a Internet das Coisas. E proporcionando flexibilidade para controlar detalhes da aplicação.</p>
<p>Porém um dos seus pontos fracos está na sua data de origem. Tendo surgido por volta do início de 2014, é de se esperar que não seja uma plataforma muito madura ainda. Ao navegar pelo site oficial, é fácil perceber pontos em que falta documentação, ou links que te levam a artigos completamente vazios. Ainda assim, a documentação no site é suficiente para iniciar o aprendizado. Porém, provavelmente chegará uma hora em que você sentirá falta de algumas informações, assim como eu senti.</p>
<p>Ainda assim, o Zetta aparenta ser uma plataforma simples, robusta e estável. É possível utilizá-lo para realizar uma enormidade de projetos. E é uma ótima escolha para aqueles que estão iniciando com a Internet das Coisas, ou apenas querem matar a curiosidade.</p>
<p>Outra vantagem para o Zetta é que, diferente de muitas plataformas com propósitos puramente comerciais, esse é um projeto Open Source (utilizando a licensa MIT) e sem fins comerciais (apesar de que você pode, sim, usá-lo para criar aplicações comerciais). E é um projeto que está em constante desenvolvimento.</p>
<p>Mas a falta de uma grande empresa por trás do Zetta pode dificultar o seu uso em aplicações de larga escala. Por falta, por exemplo, de um suporte dedicado exclusivamente a atender seus clientes e a falta de garantia de funcionamento.</p>
<h2 id="Arquitetura-do-Zetta"><a href="#Arquitetura-do-Zetta" class="headerlink" title="Arquitetura do Zetta"></a>Arquitetura do Zetta</h2><p>A arquitetura de uma aplicação Zetta é basicamente a seguinte: existe um servidor Zetta central executando na nuvem (no Heroku, por exemplo), que está conectado a alguns Hubs (como um Raspberry Pi ou um Beaglebone) que rodam instâncias locais de um servidor Zetta. Esses Hubs por sua vez estão conectados a equipamentos eletrônicos e sensores (como exemplo, uma célula fotovoltaica e uma LED). Vejam isso ilustrado na <strong>INCRÍVEL</strong> figura que eu fiz:</p>
<p><img src="/images/arquitetura-do-zetta.jpg" alt="Arquitetura do Zetta"></p>
<p>Dessa maneira, dados são obtidos dos diversos equipamentos e sensores e levados aos servidores dos hubs, que os encaminha ao servidor central. Isso funciona de forma geo-distribuída, então é possível que, por exemplo, um sensor fotovoltaico lá no japão faça com que uma lâmpada acenda aqui no Brasil.</p>
<p>Essa lógica, de como as coisas acontecem e em função do quê, está toda nos servidores, podendo estar até mesmo distribuída entre os hubs e o servidor central.</p>
<h2 id="Demonstracao"><a href="#Demonstracao" class="headerlink" title="Demonstração"></a>Demonstração</h2><p>Para exemplificar o uso do Zetta, eu desenvolvi uma aplicação simples, baseada no <a href="http://www.zettajs.org/projects/2014/10/13/Hello-World.html" target="_blank" rel="external">tutorial para iniciantes</a> disponível no site oficial. E adicionalmente, incrementei com uma funcionalidade a mais (controlar o player do meu PC), para exemplificar a criação de drivers.</p>
<p>O exemplo disponibilizado no site ensina a criar um servidor local que irá servir para ilustrar uma aplicação que controla a luminosidade de um local. No exemplo é utilizado uma mock LED juntamente com uma mock photocell (célula voltaica), de maneira que quando a photocell detecta uma baixa luminosidade, a LED acende. E quando a photocell detecta elevada luminosidade, a LED apaga.</p>
<p>Para aqueles que não estão familiarizados com o termo, “mock” nesse contexto, quer dizer que não há hardware sendo utilizado. Nem para a photocell, e nem para a LED. Os drivers utilizados procuram simular os comportamentos desses dispositivos. Por isso, é necessário apenas um computador para executar o projeto e ver tudo funcionando.</p>
<p>Apesar do exemplo, parecer algo simples demais, este exemplo serve bem para ilustrar uma possível aplicação na vida real. Para fazer algo mais útil, você poderia colocar uma célula voltaica verdadeira no telhado da sua casa, e no lugar de uma LED, você usaria algumas lâmpadas da sua casa. Dessa forma, quando a noite chegasse, as lâmpadas da sua casa acenderiam automaticamente. E quando o dia chegasse, elas apagariam, sem a necessidade de qualquer intervenção.</p>
<p>Se você fosse utilizar um dispositivo real qualquer, conectado ao seu hub, então você precisaria de um driver específico que fizesse a comunicação entre o servidor local e o dispositivo. Há uma variedade de drivers já criados para vários dispositivos e plataformas diferentes. Mas se você não encontrar um que atenda sua necessidade, poderá desenvolver o seu próprio. No projeto que eu desenvolvi, eu exemplifiquei a criação de um driver simples. Porém dependendo da sua necessidade, um pouco de conhecimento de eletrônica poderá ser necessário. Algo que eu não sei, e não tenho como ensinar.</p>
<p>No projeto, além da funcionalidade básica de controle de luminosidade, eu desenvolvi um driver que pudesse controlar o player de mídia do meu computador (o <a href="http://banshee.fm/" target="_blank" rel="external">Banshee</a>). Infelizmente, devido a forma como eu desenvolvi o driver, essa última parte irá funcionar apenas em sistemas operacionais Linux. E que tenham o Banshee instalado… é claro!</p>
<p>O driver permite pausar a reprodução e voltar a reproduzir a faixa atual. Além de permitir pular para a próxima faixa ou voltar a anterior.</p>
<p>Imaginando o contexto de Internet das Coisas, podemos imaginar várias aplicações. A minha localização poderia ser monitorada pelo GPS do meu celular, por exemplo. E quando eu estivesse voltando do trabalho, ao chegar próximo de casa, uma música poderia começar a tocar automaticamente em casa. E da mesma forma, parasse quando eu estivesse saindo.</p>
<h2 id="Execucao-do-projeto"><a href="#Execucao-do-projeto" class="headerlink" title="Execução do projeto"></a>Execução do projeto</h2><p>Todo o <a href="https://github.com/possatti/sample-zettajs-server/" target="_blank" rel="external">código da aplicação</a> está hospedado no github. E também o <a href="https://github.com/possatti/zetta-banshee-driver" target="_blank" rel="external">driver para o Banshee</a>. Para executar o projeto, entre com os comandos abaixo na sua linha de comando. Você precisará instalar no seu computador o <a href="https://nodejs.org/" target="_blank" rel="external">Node</a> e o <a href="https://www.npmjs.com/" target="_blank" rel="external">NPM</a> (que geralmente já vem com o Node).</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Clone o projeto</span></span><br><span class="line">$ git <span class="built_in">clone</span> https://github.com/possatti/sample-zettajs-server.git</span><br><span class="line"><span class="comment"># Entre no diretório baixado</span></span><br><span class="line">$ <span class="built_in">cd</span> sample-zettajs-server</span><br><span class="line"><span class="comment"># Instale as dependências necessárias (inclusive o driver</span></span><br><span class="line"><span class="comment"># para o banshee)</span></span><br><span class="line">$ npm install</span><br><span class="line"><span class="comment"># Inicie o servidor:</span></span><br><span class="line">$ npm start</span><br></pre></td></tr></table></figure>
<p>Se você não tiver o git instalado em seu computador. Não há problema. Você pode baixar o <a href="https://github.com/possatti/sample-zettajs-server/archive/v0.1.zip" target="_blank" rel="external">projeto no github</a> e continuar com <code>npm install</code> e <code>npm start</code>.</p>
<p>Com isso, o servidor irá iniciar em localhost, na porta 1337, por padrão. E você, de imediato, irá notar, no log da linha de comando, que a LED está acendendo e apagando toda hora. Isso está correto, a célula fotovoltaica está ocasionando esse comportamento.</p>
<p>Para visualizar tudo o que está acontecendo, eu recomendo o uso do Zetta Browser. Para abrir o Zetta Browser apontando para o seu servidor local (127.0.0.1:1337), entre com o seguinte endereço no seu navegador:</p>
<p><a href="http://browser.zettajs.io/#/overview?url=http://127.0.0.1:1337" target="_blank" rel="external">http://browser.zettajs.io/#/overview?url=http://127.0.0.1:1337</a></p>
<p>Mas lembre que isso que você está visualizando é tudo local, apenas. Para realmente ser capaz de acessar este hub através da internet, o servidor local precisa se conectar a um servidor na nuvem. Coisa que esse projeto já está configurado para fazer. Ao ter iniciado o servidor local, ele automaticamente já se conectou ao servidor em hello-zetta.herokuapp.com (isto está configurado no código do projeto). Este servidor do <a href="https://heroku.com/" target="_blank" rel="external">Heroku</a> é disponibilizado pela equipe desenvolvedora do Zetta, para que iniciantes possam usá-lo. Então qualquer um pode criar sua aplicação e se conectar a ele.</p>
<p>Para acessar a API do servidor local através da internet, use o Zetta Browser apontando para o servidor do Heroku:</p>
<p><a href="http://browser.zettajs.io/#/overview?url=http://hello-zetta.herokuapp.com" target="_blank" rel="external">http://browser.zettajs.io/#/overview?url=http://hello-zetta.herokuapp.com</a></p>
<p>Com essa URL, você poderá usar o seu celular, por exemplo, para visualizar a LED e a photocell. Além de poder interagir com o Banshee, se você o tiver instalado.</p>
<p>Mas, por favor, tenha em mente, que como esta é apenas uma aplicação de demonstração, nenhuma etapa de autenticação é feita. Isto quer dizer que qualquer pessoa em qualquer parte do mundo pode acessar a API que o seu servidor local está provendo. Apesar de que isso não é tão alarmante, pois as únicas coisas que eles podem fazer é controlar a mock LED e o Banshee no seu computador.</p>
<h2 id="E-agora"><a href="#E-agora" class="headerlink" title="E agora?"></a>E agora?</h2><p>Para aprender mais, você pode continuar interagindo com o servidor, e investigar o código, para ver como o projeto funciona. Conhecimentos de NodeJS e JavaScript com certeza irão lhe ajudar. Para aprender mais sobre o Zetta, um bom ponto de partida é o seu próprio <a href="http://www.zettajs.org/" target="_blank" rel="external">site</a>, apesar de que, como eu disse, a documentação do projeto falha em alguns pontos.</p>
<p>E se estiver interessado, você pode tentar construir sua própria aplicação, segundo uma necessidade ou um desejo que você tem. Comesse com algo simples e vá aperfeiçoando a medida que desejar.</p>
Introdução a internet das coisas, e exemplo de aplicação utilizando o Zetta.
Git Pro Tip: Diretórios vazioshttp://possatti.com.br/git-pro-tip-diretorios-vazios/2015-03-26T00:05:29.000Z2016-06-24T22:25:13.011Z<p><img src="/images/git-logo.png" alt=""></p>
<p>Nesse post vou falar sobre algo que me aborrecia quando comecei a usar o git. E que pode trazer dificuldades para outros que estejam iniciando com o git. Falarei sobre o fato de que ele não registra diretórios vazios no repositório.</p>
<h2 id="O-problema"><a href="#O-problema" class="headerlink" title="O problema"></a>O problema</h2><p>Vamos supor a seguinte situação. Você tem um repositório do git, e acabou de criar um diretório vazio dentro dele. E ao tentar gravar suas mudanças, o git simplesmente não detecta que você criou um novo diretório. Como no exemplo:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Cria um diretório vazio</span></span><br><span class="line">$ mkdir novo_dir</span><br><span class="line"><span class="comment"># Revela o que há no diretório atual</span></span><br><span class="line">$ ls</span><br><span class="line">novo_dir</span><br><span class="line"><span class="comment"># Verifica o status do repositório</span></span><br><span class="line">$ git status</span><br><span class="line">On branch master</span><br><span class="line"></span><br><span class="line">Initial commit</span><br><span class="line"></span><br><span class="line">nothing to commit (create/copy files and use <span class="string">"git add"</span> to track)</span><br></pre></td></tr></table></figure>
<p>Como podem ver, no exemplo, o diretório vazio foi criado. Mas quando usamos o comando <code>git status</code>, ele simplesmente não detecta que um novo diretório foi criado.</p>
<p>A razão disso é simples. O git registra apenas arquivos e não diretórios. Se a minha memória não me falha, no SVN você poderia criar diretórios vazios no repositório. Mas não é o caso do git. Pois tudo o que ele busca, para gravar, são arquivos. Então ele nem mesmo se preocupa com o fato de que você criou um novo diretório. Mas se você colocasse um arquivo ali dentro, aí sim, ele detectaria o arquivo e consequentemente o diretório que o contém.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Cria um arquivo no novo diretório</span></span><br><span class="line">$ touch novo_dir/exemplo.txt</span><br><span class="line"><span class="comment"># Verifica o status do repositório</span></span><br><span class="line">$ git status</span><br><span class="line">On branch master</span><br><span class="line"></span><br><span class="line">Initial commit</span><br><span class="line"></span><br><span class="line">Untracked files:</span><br><span class="line"> (use <span class="string">"git add <file>..."</span> to include <span class="keyword">in</span> what will be committed)</span><br><span class="line"></span><br><span class="line"> novo_dir/</span><br><span class="line"></span><br><span class="line">nothing added to commit but untracked files present (use <span class="string">"git add"</span> to track)</span><br></pre></td></tr></table></figure>
<p>Vejam que neste último comando ele detectou o diretório, mas somente por causa do arquivo. O que ele irá gravar, na realidade, é o arquivo. E uma das informações relevantes para gravar o arquivo é onde ele está.</p>
<h2 id="Porque-isso-me-incomodaria"><a href="#Porque-isso-me-incomodaria" class="headerlink" title="Porque isso me incomodaria?"></a>Porque isso me incomodaria?</h2><p>Alguns podem estranhar, e se perguntar: “Mas e daí? O diretório está vazio mesmo!”. Hoje eu concordo com isso. Mas no começo isso me atrapalhava um pouco, quando eu estava começando a usar o git.</p>
<p>Como, por exemplo, quando eu estava iniciando um novo projeto e usava uma ferramenta para gerar o esqueleto do meu projeto. Assim, a ferramenta criava uma porção de diretórios onde eu deveria colocar meus arquivos. Mas se eu ainda não tivesse desenvolvido nada ainda, eu teria que deixá-los vazio por algum tempo.</p>
<p>Isso costumava acontecer comigo quando eu criava um novo projeto do <a href="https://maven.apache.org/" target="_blank" rel="external">maven</a> pelo eclipse. O eclipse criava várias pastas vazias, segundo a estrutura de um projeto padrão do maven. E essa estrutura era importante, porque ditava a forma como eu deveria organizar meu projeto. Se eu colocasse um teste no diretório errado, por exemplo, o maven não iria incorporá-lo a build. E por esse motivo, as coisas precisavam estar em seu devido lugar.</p>
<p>E quando eu tentava gravar as alterações no repositório, o git simplesmente não detectava as novas pastas que haviam sido criadas, apenas os arquivos, como o <code>pom.xml</code>. Então se eu fosse usar um outro computador, e tivesse que clonar o projeto, ele não viria com a estrutura de pastas que eu precisava. Então eu teria que resgatar tudo da minha memória, ou gastar algum tempo procurando na internet como a estrutura deveria ser.</p>
<h2 id="Solucao"><a href="#Solucao" class="headerlink" title="Solução"></a>Solução</h2><p>A verdade é que não existe uma solução elegante para isso. É uma característica do git que você deve se acostumar. E com o tempo, essa característica realmente passa a fazer sentido. Afinal de contas, para que gravar um diretório vazio? … Ele está vazio! Então não estamos perdendo nada.</p>
<p>Mas como eu expliquei, em algumas situações você pode querer subir um diretório vazio intencionalmente. Se esse for o seu caso, há algumas alternativas que podemos recorrer. Há uma <a href="http://stackoverflow.com/questions/115983/how-can-i-add-an-empty-directory-to-a-git-repository" target="_blank" rel="external">questão no Stack Overflow</a> que tem excelentes sugestões de como fazer isso. E eu vou descrever aqui duas delas que considero mais importantes.</p>
<p>Uma das possíveis soluções, é que você crie um arquivo vazio dentro da pasta, chamado <code>deletar-depois</code>, <code>placeholder</code>, ou qualquer coisa do gênero. O importante é que fique claro para você, e para sua equipe, que esse arquivo deve ser deletado assim que o diretório for preenchido com algum conteúdo importante.</p>
<p>Outra alternativa é para o caso de você querer <strong>forçar</strong> com que o diretório esteja <strong>sempre</strong> vazio (sabe se lá, porque você iria querer isso xD ). Para esta situação, você pode criar um <a href="http://git-scm.com/docs/gitignore" target="_blank" rel="external"><code>.gitignore</code></a> dentro da pasta, com o seguinte conteúdo:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Ignora tudo neste diretório</span><br><span class="line">*</span><br><span class="line"># Exceto este arquivo</span><br><span class="line">!.gitignore</span><br></pre></td></tr></table></figure>
<p>Nessa última alternativa, ninguém nunca irá conseguir gravar um arquivo nessa pasta! A não ser que o <code>.gitignore</code> seja apagado, posteriormente. Isso pois o git irá ignorar todos os arquivos ali dentro, com exceção do <code>.gitignore</code>.</p>
<p>Dada essas duas soluções, eu encerro aqui. Espero que essa dica seja útil. E se tiverem dúvidas, ou quiserem compartilhar alguma experiência própria, podem escrever aqui nos comentários.</p>
O git não grava pastas vazias em seus repositórios. Entenda porquê, e como contornar o problema.
Jekyllhttp://possatti.com.br/jekyll/2014-08-22T10:27:29.000Z2015-03-25T07:56:29.000Z<p><img src="/images/jekyll-logo.png" alt=""></p>
<p>Nesse primeiro post eu resolvi escrever sobre a ferramenta (Jekyll) que eu usei para criar o meu primeiro blog, e como ela pode ser útil para vários propósitos.</p>
<h3 id="O-que-e-o-Jekyll"><a href="#O-que-e-o-Jekyll" class="headerlink" title="O que é o Jekyll?"></a>O que é o Jekyll?</h3><p>O <a href="http://jekyllrb.com/" target="_blank" rel="external">Jekyll</a> é um gerador de websites estáticos. Em poucas palavras, o que ele faz é converter um monte de html, css, javascript, markdown, etc em um website estático. Para usa-lo, você define templates para exibir diferentes tipos de publicações, e define o conteúdo separadamente.</p>
<p>Já que você irá definir a parte bruta através de HTML, CSS e JavaScript, isso te permite ter controle total sobre o estilo do website. Ao mesmo tempo que te permite publicar todo o tipo de conteúdo que você definir.</p>
<p>Você ganha praticidade quando resolve esquematizar o projeto, dividindo-o em templates e conteúdo. Por exemplo, você pode definir um template para posts de um blog, e define o conteúdo dos posts usando uma linguagem mais simples como <a href="http://en.wikipedia.org/wiki/Markdown" target="_blank" rel="external">markdown</a> ou <a href="http://en.wikipedia.org/wiki/Textile_%28markup_language%29" target="_blank" rel="external">textile</a> (markdown é o mais usado). Assim, o Jekyll irá se responsabilizar por processar esse conteúdo e enquadra-lo na definição do seu template de posts. Com isso, o resultado final é uma página html completa com o seu conteúdo. Você pode inclusive ter mais de uma definição de template para posts, e em cada post especificar qual template você deseja usar.</p>
<p>O foco principal do Jekyll está na criação de blogs, mas ele também pode ser usado para projetos mais ambiciosos como por exemplo <a href="http://www.developmentseed.org/blog/new-healthcare-gov-is-open-and-cms-free/" target="_blank" rel="external">o projeto que o grupo Development Seed fez</a> para criar o portal <a href="https://www.healthcare.gov/" target="_blank" rel="external">HealthCare.gov</a> para o governo norte americano.</p>
<p>Ferramentas como essa parecem estar ganhado uma popularidade cada vez maior, como alternativas a CMSs (Content Management System), como o <a href="http://wordpress.org/" target="_blank" rel="external">Wordpress</a> e o <a href="https://www.drupal.org/" target="_blank" rel="external">Drupal</a>. Pois elimina elementos custosos do desenvolvimento e da manutenção, ao mesmo tempo que te permite um maior controle sobre a estrutura do website. Como exemplo, em um website estático você não precisa se preocupar com um banco de dados. Assim você elimina o custo de ter um, e também de ter pessoas que saibam usá-lo.</p>
<p>Porém, com isso você pode acabar perdendo alguma funcionalidade dinâmica de um CMS, que a princípio necessite de uma aplicação do lado do servidor. Mas você pode facilmente compensar isso usando APIs de terceiros para compor o seu website. Uma funcionalidade comum de um CMS é a gestão de comentários nas páginas. Mas como você poderia alcançar o mesmo efeito em um site totalmente estático? Você pode usar uma API como a do <a href="https://disqus.com/" target="_blank" rel="external">Disqus</a>, que vem ganhando bastante popularidade recentemente, ou a do <a href="https://developers.facebook.com/docs/plugins/comments" target="_blank" rel="external">Facebook</a>. Assim, no final das contas, o que você tem é um pequeno código HTML-JavaScript que você joga em seu template, e assim todas as páginas ganham uma seção de comentários. Uhuul!</p>
<p>Mas fazer a escolha entre utilizar um CMS ou um gerador de sites estáticos é uma decisão delicada, e que deve ser pensada com cuidado, tendo em vista o objetivo final do projeto.</p>
<h3 id="Personalizacao-do-projeto"><a href="#Personalizacao-do-projeto" class="headerlink" title="Personalização do projeto"></a>Personalização do projeto</h3><p>É possível ainda, acrescentar outras ferramentas no ciclo de vida do seu projeto. Deixando o desenvolvimento mais a seu próprio gosto. Por exemplo, você pode combinar pre-processadores (como o <a href="http://lesscss.org/" target="_blank" rel="external">Less</a> ou <a href="http://sass-lang.com/" target="_blank" rel="external">Sass</a>) para a sua build.</p>
<p>E se você não quiser se preocupar com o desenvolvimento bruto do site, você pode simplesmente escolher um tema já pronto, e se preocupar apenas com o conteúdo. Mas isso te limita a usar o que outras pessoas já criaram.</p>
<p>Existem vários temas para o Jekyll já prontos, a grande maioria deles focada em blogs. Basta escolher um deles, e começar a publicar… como eu fiz ;) . Mas se você tiver os conhecimentos necessários, você pode se aventurar e criar o seu próprio tema, e assim construir tudo completamente personalizado.</p>
<p>E como eu disse, há vários temas espalhados pela internet (você pode dar uma olhada <a href="http://jekyllthemes.org/" target="_blank" rel="external">nesse link</a> para conferir vários deles) feitos por diversas pessoas que resolveram compartilhar seus trabalhos. Há alguns bem simples e outros mais elaborados e de muito bom gosto. Cabe a você escolher.</p>
<p>Mas já adianto que se você pretende criar algo muito diferente de um blog, você provavelmente terá que criar tudo manualmente. Isso não é problema do Jekyll em si, pois ele suporta a geração de diversos tipos de conteúdo, e é possível customiza-lo para o que for necessário. Mas se o que você quer for muito específico é provável que você não encontrará nada pronto pela internet.</p>
<p>Se o Jekyll não te atender em algum aspecto você pode experimentar outros geradores de sites estáticos como: <a href="http://octopress.org/" target="_blank" rel="external">Octopress</a> (usa o Jekyll), <a href="http://hexo.io/" target="_blank" rel="external">Hexo</a>, <a href="http://nanoc.ws/" target="_blank" rel="external">nanoc</a>, entre <a href="http://staticsitegenerators.net/" target="_blank" rel="external">vários outros</a>.</p>
<h3 id="Como-usar"><a href="#Como-usar" class="headerlink" title="Como usar"></a>Como usar</h3><p>Não adianta chorar, você provavelmente terá que sujar as mãos em algum momento e usar a linha de comando. Mas não é difícil como algumas pessoas pensam. Logo, pare de reclamar, se for o seu caso, e siga em frente. ¬¬</p>
<p>Para exemplificar o uso do Jekyll, vou descrever aqui como criar e gerenciar um blog simples, sem nada demais. Assim você terá conhecimento de como ele funciona, e poderá, então, escolher se irá personalizar tudo na mão ou pegar um tema já pronto e pular o trabalho duro. De qualquer forma, é útil ter um conhecimento de como ele funciona.</p>
<p>O primeiro passo de todos é instala-lo na sua máquina. Para isso consulte as <a href="http://jekyllrb.com/docs/installation/" target="_blank" rel="external">intruções de instalação</a> no site oficial. Lá você encontra instruções detalhadas para a instalação na sua plataforma específica.</p>
<p>Porém, um método fácil de instala-lo é usando o RubyGem (gerenciador de pacotes da linguagem Ruby), através de um único comando:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Talvez você tenha que usar sudo</span></span><br><span class="line">$ gem install jekyll</span><br></pre></td></tr></table></figure>
<p>Após isso, basta um comando para criar um novo projeto:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ jekyll new meu-novo-blog</span><br></pre></td></tr></table></figure>
<p>Assim o jekyll irá criar um exemplo de um blog bem básico com a estrutura exemplificada abaixo (para servir as páginas em localhost basta executar <code>jekyll serve</code>).</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cd</span> meu-novo-blog</span><br><span class="line">$ tree</span><br><span class="line">.</span><br><span class="line">├── about.md</span><br><span class="line">├── _config.yml</span><br><span class="line">├── css</span><br><span class="line">│ └── main.css</span><br><span class="line">├── feed.xml</span><br><span class="line">├── _includes</span><br><span class="line">│ ├── footer.html</span><br><span class="line">│ ├── header.html</span><br><span class="line">│ └── head.html</span><br><span class="line">├── index.html</span><br><span class="line">├── _layouts</span><br><span class="line">│ ├── default.html</span><br><span class="line">│ ├── page.html</span><br><span class="line">│ └── post.html</span><br><span class="line">└── _posts</span><br><span class="line"> └── 2014-08-30-welcome-to-jekyll.markdown</span><br></pre></td></tr></table></figure>
<p>Então, permita-me explicar um pouco sobre essa estrutura. <code>_config.yml</code> é o arquivo de configuração do seu site, que contém informações como: nome do site, seu e-mail, plugins usados, etc. Esse arquivo utiliza a sintaxe <a href="http://pt.wikipedia.org/wiki/YAML" target="_blank" rel="external">YAML</a>. O diretório <code>_includes</code> contém “pedaços de HTML” que você usará para definir seus layouts (templates). Em <code>_layouts</code> você deve colocar os seus templates. (Os layouts são páginas quase completas, esperando apenas para receberem conteúdo.) E, finalmente, em <code>_posts</code> você define seus posts em uma linguagem simples como o markdown, por exemplo.</p>
<p>Se você investigar os arquivos html que foram gerados (em <code>_includes/</code> e <code>_layouts/</code>), verá que neles foi usado uma notação diferente no meio do html (um monte de chaves <code>{}</code> espalhados). Isso que está sendo usado, são tags <a href="http://liquidmarkup.org/" target="_blank" rel="external">Liquid</a>. Elas são <a href="http://jekyllrb.com/docs/templates/" target="_blank" rel="external">usadas pelo Jekyll para a definição dos templates</a>. Você precisará entender como elas funcionam para quando você quiser criar os seus próprios templates. Mas não são necessárias quando você estiver escrevendo seus posts.</p>
<p>Você pode notar também que quando executamos <code>jekyll new</code>, ele criou uma página inicial (<code>index.html</code>) e um <code>about.md</code> (que quando processado se tornará <code>about.html</code>). Além disso, ele gerou um exemplo de um post para você em <code>_posts/</code>.</p>
<p>A essa altura você deve querer visualizar o resultado de tudo isso. Então vamos em frente, e depois voltamos para esclarecer mais algumas coisas. Para gerar o website estático é necessário apenas executar o comando <code>jekyll build</code> e o jekyll irá processar todos os seus arquivos e gerar o resultado no diretório <code>_site</code>. Isso só já basta para você conseguir o que realmente importa (um website estático), mas vamos fazer um pouco mais do que isso, e vamos executar <code>jekyll serve</code>. Assim ele irá servir em localhost os arquivos gerados, para que você possa visualizar o site. Então, depois desse último comando, abra o navegador e entre em <code>localhost:4000</code>, por padrão, e veja o seu mais novo blog! Tcharaaam!</p>
<p>Repare que é possível executar <code>jekyll serve --watch</code> para que o Jekyll fique “assistindo” o diretório do projeto. E quando qualquer mudança acontecer (quando você editar um post, por exemplo), ele irá gerar novamente os arquivos necessários. O único arquivo que ele não irá assistir é o <code>_config.yml</code>. E também repare que não é necessário executar <code>jekyll build</code> antes de <code>jekyll serve</code>, pois esse último já executa a build automaticamente.</p>
<p>Entenda o que o Jekyll fez. Ele construiu o site, em basicamente duas etapas. Primeiramente, ele tomou todos os arquivos que necessitavam de processamento (os arquivos em markdown e textile) e os processou combinando com os layouts e includes necessários, gerando arquivos de html para cada um deles. Repare que os diretórios de destino dos posts é diferente do comum, o Jekyll usa o nome do post para criar diretórios de destino para eles. Isso da seguinte forma, se você tem um post chamado <code>2014-10-19-exemplo.md</code> ele será processado e irá parar em <code>_site/2014/10/19/exemplo.html</code>. Mas fora isso, todos os arquivos vão parar em lugares segundo suas posições relativas ao diretório raiz do projeto (exemplo: <code>/about/index.md</code> é processado e vai parar em <code>_site/about/index.html</code>) da forma como você esperaria.</p>
<p>A segunda etapa da build é mais simples. Ele copia todos os arquivos que não necessitam de processamento, como imagens, css, javascript, etc, para o diretório <code>_site/</code>. Então, por exemplo, um arquivo <code>/imagens/foto.jpg</code> vai parar em <code>_site/imagens/foto.jpg</code>).</p>
<h3 id="YAML-Front-Matter"><a href="#YAML-Front-Matter" class="headerlink" title="YAML Front Matter"></a>YAML Front Matter</h3><p>Mas que tipo de arquivos são processados pelo Jekyll exatamente? E quais são simplesmente copiados sem processamento? Por definição do Jekyll, somente são processados os arquivos com extenções do markdown ou textile, e os arquivos que tenham um cabeçalho especial, chamado de <a href="http://jekyllrb.com/docs/frontmatter/" target="_blank" rel="external">“YAML Front Matter”</a>. Quando o Jekyll detectar esse tipo de cabeçalho ele irá processar o arquivo. Um “front matter” deve ser colocada logo no começo do arquivo e se parece com o seguinte:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">layout: post</span><br><span class="line">title: "Jekylll"</span><br><span class="line">modified: 2014-08-22 07:27:29 -0300</span><br><span class="line">tags: [jekyll]</span><br><span class="line">comments: true</span><br><span class="line">---</span><br></pre></td></tr></table></figure>
<p>A sintaxe utilizada para a codificação do “Front Matter” é a <a href="http://pt.wikipedia.org/wiki/YAML" target="_blank" rel="external">YAML</a> (assim como o arquivo <code>_config.yml</code>). E nessa seção você pode definir variaveis que serão utilizadas pelo Jekyll (como <code>layout</code> e <code>title</code>). E, até mesmo, variáveis personalizadas, como é o caso do exemplo acima em que a variável <code>comments</code> é utilizada pelo meu tema atual, para saber quando ele deve incluir uma seção de comentários, ou não, em um post.</p>
<p>E se você quiser que o arquivo seja processado, mas ele não precisa de nenhuma variável, você ainda assim precisa de incluir o front matter. Mas pode deixa-lo vazio, sem nenhuma variável. Isso pode ser útil quando você quer usar Liquid Tags em arquivos css e javascript, por exemplo.</p>
<h3 id="Hospedagem-no-Github-Pages"><a href="#Hospedagem-no-Github-Pages" class="headerlink" title="Hospedagem no Github Pages"></a>Hospedagem no Github Pages</h3><p>Ok… mas e depois que você criar o seu website e quiser publicá-lo na internet? Você pode optar por várias possibilidades, inclusive a de usar o seu próprio servidor pessoal. Porém, o que eu considero mais prático, no momento, é utilizar a hospedagem gratuita do <a href="https://pages.github.com/" target="_blank" rel="external">Github Pages</a>. Para mim, a forma mais simples para publicar seu site, é você criar um repositório na sua conta do GitHub chamado <code><seu-nome-de-usuario>.github.io</code> e subir o seu projeto do Jekyll para o novo repositório. O GitHub irá processar o seu projeto do Jekyll e gerar o seu website estático no endereço <code><seu-nome-de-usuario>.github.io</code>. Simples assim. Apenas preste atenção na versão do Jekyll que você está usando e a versão que está sendo usada pelo GitHub (confira <a href="https://pages.github.com/versions/" target="_blank" rel="external">aqui</a>). Mas isso não deve ser um problema.</p>
<p>Se preferir, você pode construir o site na sua máquina e subir o resultado final para o GitHub Pages. Isso é uma outra possibilidade. Assim, você tem controle de qual versão do Jekyll utilizar, e também usar plugins em sua build (coisa que o github bloqueia para evitar que plugins maliciosos executem). Você pode até usar um domínio personalizado se quiser. Para entender melhor como o GitHub Pages funciona, leia a <a href="https://pages.github.com/" target="_blank" rel="external">página oficial do Github Pages</a>.</p>
<h3 id="O-que-fazer-depois"><a href="#O-que-fazer-depois" class="headerlink" title="O que fazer depois?"></a>O que fazer depois?</h3><p>Se você não sabe para onde ir agora, e o que fazer para aprender mais, eu te aconselho a brincar com o blog que criamos nesse tutorial. Crie um novo post; dê uma olhada em como funcionam os layouts e includes; futuque as Liquid Tags e veja como elas funcionam; etc.</p>
<p>Se você ainda tiver dúvidas ou quiser entender melhor as coisas, eu recomendo que você dê uma olhada na <a href="http://jekyllrb.com/docs/home/" target="_blank" rel="external">documentação do Jekyll</a> (em inglês). A documentação é boa, e fala sobre vários aspectos da ferramenta. E tudo está escrito de forma clara e concisa.</p>
<p>É isso aí! Até mais. :)</p>
Breve introdução ao Jekyll, um gerador de websites estáticos, com foco em blogs.