You are here:
Wiki-SL
>
TWikiBar Web
>
BatePapos
>
TWikiBarPapo001
(01 Aug 2009,
BrSalgado
)
(raw view)
E
dit
A
ttach
---+!! Papo de Botequim - Parte I %TOC% ---++ Diálogo entreouvido entre um Linuxer e em empurrador de mouse: - Quem é o _Bash_? - O _Bash_ é o filho mais novo da família _Shell_. - Pô cara! Estás a fim de me deixar maluco? Eu tinha uma dúvida e você me deixa com duas! - Não, maluco você já é há muito tempo. Desde que se decidiu a usar aquele sistema operacional que você tem que dar dez _boots_ por dia e não tem domínio nenhum sobre o que esta acontecendo no seu computador. Mas deixa isso prá lá, vou te explicar o que é _Shell_ e os componentes de sua família e ao final da explanação você dirá: "Meu Deus do _Shell_! Porque eu não optei pelo _Linux_ antes?". ---++ O Ambiente Linux Para você entender o que é e como funciona o _Shell_, primeiro vou te mostrar como funciona o ambiente em camadas do _Linux_. Dê uma olhada no gráfico abaixo: <center><img src="%PUBURL%/%WEB%/FreeSkinImagens/grafico.png" alt="Visão do shell em relação do Kernel do Linux" /></center> Neste gráfico dá para ver que a camada de __hardware__ é a mais profunda e é formada pelos componentes físicos do seu computador. Envolvendo esta, vem a camada do __kernel__ que é o cerne do _Linux_, seu núcleo, e é quem bota o _hardware_ para funcionar, fazendo seu gerenciamento e controle. Os *programas* e *comandos* que envolvem o _kernel_, dele se utilizam para realizar as tarefas aplicativas para que foram desenvolvidos. Fechando tudo isso vem o __Shell__ que leva este nome porque em inglês, _Shell_ significa concha, carapaça, isto é, fica entre o usuário e o sistema operacional, de forma que tudo que interage com o sistema operacional, tem que passar pelo seu crivo. ---++ O Ambiente _Shell_ Bom já que para chegar ao núcleo do _Linux_, no seu _kernel_ que é o que interessa a todo aplicativo, é necessária a filtragem do _Shell_, vamos entender como ele funciona de forma a tirar o máximo proveito das inúmeras facilidades que ele nos oferece. O _Linux_ por definição é um sistema *multiusuário* - não podemos nunca esquecer disto – e para permitir o acesso de determinados usuários e barrar a entrada de outros, existe um arquivo chamado =/etc/passwd= que além fornecer dados para esta função de "leão-de-chácara" do _Linux_, também provê informações para o _login_ daqueles que passaram por esta primeira barreira. O último campo de seus registros informa ao sistema qual _Shell_ a pessoa vai receber ao se "logar" (ARGH!!!). %DICA_INI% Quando eu disse que o último campo do =/etc/passwd= informa ao sistema qual é o _Shell_ que o usuário vai receber ao se "logar", é para ser interpretado ao pé-da-letra, isto é, se neste campo do seu registro estiver =prog=, a pessoa ao acessar o sistema receberá a tela de execução do programa =prog= e ao terminar a sua execução ganhará imediatamente um logout. Imagine o quanto se pode incrementar a segurança com este simples artifício. %DICA_FIM% Lembra que eu te falei de _Shell_, família, irmão? Pois é, vamos começar a entender isto: o _Shell_, que se vale da imagem de uma concha envolvendo o sistema operacional propriamente dito, é o nome genérico para tratar os filhos desta idéia que, ao longo dos anos de existência do sistema operacional _Unix_ foram aparecendo. Atualmente existem diversos sabores de _Shell_, dentre estes eu destaco o *sh* (Bourne Shell), o *ksh* (Korn Shell), *bash* (Bourne Again Shell) e o *csh* (C Shell). ---+++ Uma Rapidinha nos Principais Sabores de _Shell_ ---++++ Bourne Shell (sh) Desenvolvido por Stephen Bourne da Bell Labs (da AT&T onde também foi desenvolvido o _Unix_), este foi durante muitos anos o _Shell default_ do sistema operacional _Unix_. É também chamado de _Standard Shell_ por ter sido durante vários anos o único e até hoje é o mais utilizado até porque ele foi portado para todos os ambientes _Unix_ e distros _Linux_. ---++++ Korn Shell (ksh) Desenvolvido por David Korn, também da _Bell Labs_, é um superset do sh, isto é, possui todas as facilidades do sh e a elas agregou muitas outras. A compatibilidade total com o sh vem trazendo muitos usuários e programadores de _Shell_ para este ambiente. ---++++ Boune Again Shell (bash) Este é o _Shell_ mais moderno e cujo número de adeptos mais cresce em todo o mundo, seja por ser o _Shell default_ do _Linux_, seu sistema operacional hospedeiro, seja por sua grande diversidade de comandos, que incorpora inclusive diversos instruções características do C Shell. ---++++ C Shell (csh) Desenvolvido por Bill Joy da Berkley University é o _Shell_ mais utilizado em ambientes _*BSD_ e _Xenix_. A estruturação de seus comandos é bem similar à da linguagem C. Seu grande pecado foi ignorar a compatibilidade com o sh, partindo por um caminho próprio. Além destes _Shells_ existem outros, mas irei falar contigo somente sobre os três primeiros, tratando-os genericamente por _Shell_ e assinalando as especificidades de cada um que porventura hajam. ---+++ Explicando o funcionamento do _Shell_ O _Shell_ é o primeiro programa que você ganha ao se "logar" no _Linux_. É ele que vai resolver um monte de coisas de forma a não onerar o _kernel_ com tarefas repetitivas, aliviando-o para tratar assuntos mais nobres. Como cada usuário possui o seu próprio _Shell_ interpondo-se entre ele e o _Linux_, é o _Shell_ quem interpreta os comandos que são teclados e examina as suas sintaxes, passando-os esmiuçados para execução. - Êpa! Esse negócio de interpreta comando não tem nada a haver com interpretador não, né? - Tem sim, na verdade o _Shell_ é um interpretador (ou será intérprete) que traz consigo uma poderosa linguagem com comandos de alto nível, que permite construção de _loops_ (laços), de tomadas de decisão e de armazenamento de valores em variáveis, como vou te mostrar. Vou te explicar as principais tarefas que o _Shell_ cumpre, na sua ordem de execução. Preste atenção nesta ordem porque ela é fundamental para o entendimento do resto do nosso bate papo. ---++++ Exame da Linha de Comandos Neste exame o _Shell_ identifica os caracteres especiais (reservados) que têm significado para interpretação da linha, logo após verifica se a linha passada é uma atribuição ou um comando. ---+++++ Atribuição Se o _Shell_ encontra dois campos separados por um sinal de igual (===) *sem espaços em branco entre eles*, identifica esta seqüência como uma atribuição. Exemplos %TERMINAL_INI% $ ls linux %OUT_INI%linux%OUT_FIM% %TERMINAL_FIM% Neste exemplo o _Shell_ identificou o =ls= como um programa e o _linux_ como um parâmetro passado para o programa =ls=. %TERMINAL_INI% $ valor=1000 %TERMINAL_FIM% Neste caso, por não haver espaços em branco (já dá para notar que o branco é um dos caracteres reservados) o _Shell_ identificou uma atribuição e colocou =1000= na variável =valor=. %DICA_INI% *Jamais Faça:* %TERMINAL_INI% $ valor = 1000 %OUT_INI%bash: valor: not found%OUT_FIM% %TERMINAL_FIM% Neste caso, o _Bash_ achou a palavra valor isolada por brancos e julgou que você estivesse mandando executar um programa chamado valor, para o qual estaria passando dois parâmetros: === e =1000=. %DICA_FIM% ---+++++ Comando Quando uma linha é digitada no _prompt_ do _Linux_, ela é dividida em pedaços separados por espaço em branco: o primeiro pedaço é o nome do programa que terá sua existência pesquisada; identifica em seguida, nesta ordem, opções/parâmetros, redirecionamentos e variáveis. Quando o programa identificado existe, o _Shell_ verifica as permissões dos arquivos envolvidos (inclusive o próprio programa), dando um erro caso você não esteja credenciado a executar esta tarefa. ---++++++ Resolução de Redirecionamentos Após identificar os componentes da linha que você teclou, o _Shell_ parte para a resolução de redirecionamentos. O _Shell_ tem incorporado ao seu elenco de vantagens o que chamamos de redirecionamento, que pode ser de entrada (=stdin=), de saída (=stdout=) ou dos erros (=stderr=), conforme vou te explicar a seguir. ---++++++ Substituição de Variáveis Neste ponto, o _Shell_ verifica se as eventuais variáveis (parâmetros começados por =$=), encontradas no escopo do comando, estão definidas e as substitui por seus valores atuais. ---++++++ Substituição de Meta Caracteres Se algum metacaractere (=*=, =?= ou =[]=) foi encontrado na linha de comando, neste ponto ele será substituído por seus possíveis valores. Supondo que o único arquivo no seu diretório corrente começado pela letra =n= seja um diretório chamado =nomegrandeprachuchu=, se você fizer: %TERMINAL_INI% $ cd n* %TERMINAL_FIM% Como até aqui quem esta trabalhando a sua linha é o _Shell_ e o comando (programa) =cd= ainda não foi executado, o _Shell_ transforma o =n*= em =nomegrandeprachuchu= e o comando =cd= será executado com sucesso. ----++++++ Passa Linha de Comando para o kernel Completadas as tarefas anteriores, o _Shell_ monta a linha de comandos, já com todas as substituições feitas, chama o _kernel_ para executá-la em um novo _Shell_ (_Shell_ filho), ganhando um número de processo (PID ou _<kbd>P</kbd>rocess <kbd>ID</kbd>entification_) e permanece inativo, tirando uma soneca, durante a execução do programa. Uma vez encerrado este processo (juntamente com o _Shell_ filho), recebe novamente o controle e, exibindo um _prompt_, mostra que está pronto para executar outros comandos. ---+++ Decifrando a Pedra da Roseta Para tirar aquela sensação que você tem quando vê um _script Shell_, que mais parece uma sopa de letrinhas ou um hieróglifo vou lhe mostrar os principais caracteres especiais para que você saia por ai como o __Jean-François Champollion__ decifrando a Pedra da Roseta (dê uma <a href="http://www.google.com.br/search?num=100&hl=pt-BR&q=%22Jean-Fran%C3%A7ois+Champollion%22&btnG=Pesquisar&meta=cr%3DcountryBR" target="_blank">"googlada"</a> para descobrir quem é este cara, acho que vale a pena). ---++++ Caracteres para remoção do significado É isso mesmo, quando não desejamos que o _Shell_ interprete um caractere especial, devemos "escondê-lo" dele. Isso pode ser feito de três formas distintas: ---+++++ Apóstrofo ou plic (='=) Quando o _Shell_ vê uma cadeia de caracteres entre apóstrofos (='=), ele tira os apóstrofos da cadeia e não interpreta seu conteúdo. %TERMINAL_INI% $ ls linux* %OUT_INI%linuxmagazine%OUT_FIM% $ ls 'linux*' %OUT_INI%bash: linux* no such file or directory%OUT_FIM% %TERMINAL_FIM% No primeiro caso o _Shell_ "expandiu" o asterisco e descobriu o arquivo =linuxmagazine= para listar. No segundo, os apóstrofos inibiram a interpretação do _Shell_ e veio a resposta que não existe o arquivo =linux*=. ---+++++ Contrabarra ou Barra Invertida (<nop>\) Idêntico aos apóstrofos exceto que a barra invertida inibe a interpretação somente do caractere que a segue. Suponha que você acidentalmente tenha criado um arquivo chamado =*= (asterisco) – que alguns sabores de _Unix_ permitem - e deseja removê-lo. Se você fizesse: %TERMINAL_INI% $ rm * %TERMINAL_FIM% Você estaria fazendo a maior encrenca, pois o =rm= removeria todos os arquivos do diretório corrente. A melhor forma de fazer o pretendido é: %TERMINAL_INI% $ rm \* %TERMINAL_FIM% Desta forma, o _Shell_ não interpretaria o asterisco, e em conseqüência não faria a sua expansão. Faça a seguinte experiência científica: %TERMINAL_INI% $ cd /etc $ echo '*' $ echo \* $ echo * %TERMINAL_FIM% Viu a diferença? Então não precisa explicar mais. ---+++++ Aspas (="=) Exatamente igual ao apóstrofo exceto que, se a cadeia entre aspas contiver um cifrão (=$=), uma crase (=`=), ou uma barra invertida (=<nop>\=), estes caracteres serão interpretados pelo _Shell_. Não precisa se estressar, eu não te dei exemplos do uso das aspas por que você ainda não conhece o cifrão (=$=) nem a crase (=`=). Daqui para frente veremos com muita constância o uso destes caracteres especiais, o mais importante é entender o significado de cada um. ---++++ Caracteres de redirecionamento A maioria dos comandos tem uma entrada, uma saída e pode gerar erros. Esta entrada é chamada Entrada Padrão ou =stdin= e seu _default_ é o teclado do terminal. Analogamente, a saída do comando é chamada Saída Padrão ou =stdout= e seu _default_ é a tela do terminal. Para a tela também são enviadas por _default_ as mensagens de erro oriundas do comando que neste caso é a chamada Saída de Erro Padrão ou =stderr=. Veremos agora como alterar este estado de coisas. Vamos fazer um programa gago. Para isto faça: %TERMINAL_INI% $ cat %TERMINAL_FIM% O =cat= é uma instrução que lista o conteúdo do arquivo especificado para a Saída Padrão (=stdout=). Caso a entrada não seja definida, ele espera os dados da =stdin=. Ora como eu não especifiquei a entrada, ele está esperando-a pelo teclado (Entrada Padrão) e como também não citei a saída, o que eu teclar irá para a tela (Saída Padrão) fazendo desta forma, como eu havia proposto um programa gago. Experimente! ---+++++ Redirecionamento da Saída Padrão Para especificarmos a saída de um programa usamos o =>= (maior que) ou o =>>= (maior, maior) seguido do nome do arquivo para o qual se deseja mandar a saída. Vamos transformar o programa gago em um editor de textos (que pretensão heim!). :) %TERMINAL_INI% $ cat > Arq %TERMINAL_FIM% O =cat= continua sem ter a entrada especificada, portanto está aguardando que os dados sejam teclados, porém a sua saída está sendo desviada para o arquivo =Arq=. Assim sendo, tudo que esta sendo teclado esta indo para dentro de =Arq=, de forma que fizemos o editor de textos mais curto e ruim do planeta. Se eu fizer novamente: %TERMINAL_INI% $ cat > Arq %TERMINAL_FIM% Os dados contidos em =Arq= serão perdidos, já que antes do redirecionamento o _Shell_ criará um =Arq= vazio. Para colocar mais informações no final do arquivo eu deveria ter feito: %TERMINAL_INI% $ cat >> Arq %TERMINAL_FIM% %ATENCAO_INI% Como já havia lhe dito, o _Shell_ resolve a linha e depois manda o comando para a execução. Assim, se você redirecionar a saída de um arquivo para ele próprio, primeiramente o _Shell_ "esvazia" este arquivo e depois manda o comando para execução, desta forma você acabou de perder o conteúdo do seu querido arquivo. %ATENCAO_FIM% Com isso dá para notar que o =>>= (maior maior) serve para inserir texto no final do arquivo. ---+++++ Redirecionamento da Saída de Erro Padrão Assim como o _default_ do _Shell_ é receber os dados do teclado e mandar as saídas para a tela, os erros também serão enviados para a tela se você não especificar para onde deverão ser enviados. Para redirecionar os erros use =2> <nop>SaidaDeErro=. Note que entre o número =2= e o sinal de maior (=>=) não existe espaço em branco. %ATENCAO_INI% Preste atenção! Não confunda =>>= com =2>=. O primeiro anexa dados ao final de um arquivo, e o segundo redireciona a Saída de Erro Padrão (=stderr=) para um arquivo que está sendo designado. *Isso é importante!* %ATENCAO_FIM% Suponha que durante a execução de um _script_ você pode, ou não (dependendo do rumo tomado pela execução do programa), ter criado um arquivo chamado =/tmp/seraqueexiste$$=. Para não ficar sujeira no seu disco, ao final do _script_ você colocaria uma linha: %TERMINAL_INI% $ rm /tmp/seraqueexiste$$ %TERMINAL_FIM% Caso o arquivo não existisse seria enviado para a tela uma mensagem de erro. Para que isso não aconteça deve-se fazer: %TERMINAL_INI% $ rm /tmp/seraqueexiste$$ 2> /dev/null %TERMINAL_FIM% Sobre o exemplo que acabamos de ver tenho duas dicas a dar: %DICA_INI% *Dica # 1* O =$$= contém o PID, isto é, o número do seu processo. Como o _Linux_ é multiusuário, é bom anexar sempre o =$$= ao nome dos dos arquivos que serão usados por várias pessoas para não haver problema de propriedade, isto é, caso você batizasse o seu arquivo simplesmente como =seraqueexiste=, o primeiro que o usasse (criando-o então) seria o seu dono e todos os outros ganhariam um erro quando tentassem gravar algo nele. %DICA_FIM% Para que você teste a Saída de Erro Padrão direto no _prompt_ do seu _Shell_, vou dar mais um exemplo. Faça: %TERMINAL_INI% $ ls naoexiste %OUT_INI%bash: naoexiste no such file or directory%OUT_FIM% $ ls naoexiste 2> arquivodeerros $ $ cat arquivodeerros %OUT_INI%bash: naoexiste no such file or directory%OUT_FIM% %TERMINAL_FIM% Neste exemplo, vimos que quando fizemos um =ls= em =naoexiste=, ganhamos uma mensagem de erro. Após, redirecionarmos a Saída de Erro Padrão para =arquivodeerros= e executarmos o mesmo comando, recebemos somente o _prompt_ na tela. Quando listamos o conteúdo do arquivo para o qual foi redirecionada a Saída de Erro Padrão, vimos que a mensagem de erro tinha sido armazenada nele. Faça este teste ai. %DICA_INI% *Dica # 2* - Quem é esse tal de =/dev/null=? - Em _Unix_ existe um arquivo fantasma. Chama-se =/dev/null=. Tudo que é mandado para este arquivo some. Assemelha-se a um Buraco Negro. No caso do exemplo, como não me interessava guardar a possível mensagem de erro oriunda do comando =rm=, redirecionei-a para este arquivo. %DICA_FIM% É interessante notar que estes caracteres de redirecionamento são cumulativos, isto é, se no exemplo anterior fizéssemos: %TERMINAL_INI% $ ls naoexiste 2>> arquivodeerros %TERMINAL_FIM% a mensagem de erro oriunda do =ls= seria anexada ao final de =arquivodeerros=. ---+++++ Redirecionamento da Entrada Padrão Para fazermos o redirecionamento da Entrada Padrão usamos o =<= (menor que). - E prá que serve isso? - você vai me perguntar. - Deixa eu te dar um exemplo que você vai entender rapidinho. Suponha que você queira mandar um =mail= para o seu chefe. Para o chefe nós caprichamos, né? então ao invés de sair redigindo o =mail= direto no _prompt_ da tela de forma a tornar impossível a correção de uma frase anterior onde, sem querer, escreveu um "nós vai", você edita um arquivo com o conteúdo da mensagem e após umas quinze verificações sem constatar nenhum erro, decide enviá-lo e para tal faz: %TERMINAL_INI% $ mail chefe < arquivocommailparaochefe %TERMINAL_FIM% O teu chefe então receberá o conteúdo do =arquivocommailparaochefe=. ---+++++Here Document Um outro tipo de redirecionamento muito louco que o _Shell_ te permite é o chamado __here document__. Ele é representado por =<<= (menor menor) e serve para indicar ao _Shell_ que o escopo de um comando começa na linha seguinte e termina quando encontra uma linha cujo conteúdo seja unicamente o label que segue o sinal =<<=. Veja o fragmento de _script_ a seguir, com uma rotina de =ftp=: <verbatim> ftp -ivn hostremoto << fimftp user $Usuário $Senha binary get arquivoremoto fimftp </verbatim> Neste pedacinho de programa temos um monte de detalhes interessantes: 1 As opções que usei para o =ftp= (=-ivn=) servem para ele ir listando tudo que está acontecendo (=—v= de verbose), para não perguntar se você tem certeza de que deseja transmitir cada arquivo (=—i= de interactive), e finalmente a opção =—n= serve para dizer ao =ftp= para ele não solicitar o usuário e sua senha, pois esses serão informados pela instrução específica (=user=); 1 Quando eu usei o =<< fimftp=, estava dizendo o seguinte para o intérprete:%BR%- Olhe aqui _Shell_, não se meta em nada a partir daqui até encontrar o label =fimftp=. Você não entenderia nada, já que são instruções específicas do comando =ftp= e você não entende nada de =ftp=.%BR%Se fosse só isso seria simples, mas pelo próprio exemplo dá para ver que existem duas variáveis (=$Usuário= e =$Senha=), que o _Shell_ vai resolver antes do redirecionamento. Mas a grande vantagem desse tipo de construção é que ela permite que comandos também sejam interpretados dentro do escopo do _here document_, o que também contraria o que acabei de dizer. Logo a seguir explico como esse negócio funciona. Agora ainda não dá, está faltando ferramenta. 1 O comando =user= é do repertório de instruções do =ftp= e serve para passar o usuário e a senha que haviam sido lidos em uma rotina anterior a esse fragmento de código e colocados respectivamente nas duas variáveis: =$Usuário= e =$Senha=. 1 O =binary= é outra instrução do =ftp=, que serve para indicar que a transferência de =arquivoremoto= será feita em modo binário, isto é, o conteúdo do arquivo não será interpretado para saber se está em ASCII, EBCDIC, ... 1 O =get arquivoremoto= diz ao =ftp= para pegar esse arquivo em =hostremoto= e trazê-lo para o nosso host local. Se fosse para mandar o arquivo, usaríamos o comando =put=. %ATENCAO_INI% Um erro muito freqüente no uso de =labels= (como o =fimftp= do exemplo anterior) é causado pela presença de espaços em branco antes ou após o mesmo. Fique muito atento quanto a isso, por que este tipo de erro costuma dar uma boa surra no programador, até que seja detectado. Lembre-se: um =label= que se preze tem que ter uma linha inteira só para ele. %ATENCAO_FIM% - Está bem, está bem! Eu sei que dei uma viajada e entrei pelos comandos do =ftp=, fugindo ao nosso assunto que é _Shell_, mas como é sempre bom aprender e é raro as pessoas estarem disponíveis para ensinar... ---+++++ Redirecionamento de Comandos Os redirecionamentos que falamos até aqui sempre se referiam a arquivos, isto é mandavam para arquivo, recebiam de arquivo, simulavam arquivo local, ... O que veremos a partir de agora redireciona a saída de um comando para a entrada de outro. É utilíssimo e quebra os maiores galhos. Seu nome é _pipe_ (que em inglês significa tubo, já que ele encana a saída de um comando para a entrada de outro) e sua representação é uma barra vertical (=|=). %TERMINAL_INI% $ ls | wc -l %OUT_INI% 21%OUT_FIM% %TERMINAL_FIM% O comando =ls= passou a lista de arquivos para o comando =wc=, que quando está com a opção =–l= conta a quantidade de linha que recebeu. Desta forma, podemos afirmar categoricamente que no meu diretório existiam 21 arquivos. %TERMINAL_INI% $ cat /etc/passwd |sort | lp %TERMINAL_FIM% Esta linha de comandos manda a listagem do arquivo =/etc/passwd= para a entrada do comando =sort=. Este a classifica e manda-a para o =lp= que é o gerenciador do _spool_ de impressão. ---++++ Caracteres de Ambiente Quando quer priorizar uma expressão você coloca-a entre parênteses não é? Pois é, por causa da aritmética é normal pensarmos deste jeito. Mas em _Shell_ o que prioriza mesmo são as crases (=`=) e não os parênteses. Vou dar exemplos de uso das crases para você entender melhor. Eu quero saber quantos usuários estão "logados" no computador que eu administro. Eu posso fazer: %TERMINAL_INI% $ who | wc -l %OUT_INI% 8%OUT_FIM% %TERMINAL_FIM% O comando =who= passa a lista de usuários conectados para o comando =wc –l= que conta quantas linhas recebeu e lista a resposta na tela. Pois bem, mas ao invés de ter um oito solto na tela, o que eu quero é que ele esteja no meio de uma frase. Ora para mandar frases para a tela eu uso o comando =echo=, então vamos ver como é que fica: %TERMINAL_INI% $ echo "Existem who | wc -l usuários conectados" %OUT_INI%Existem who | wc -l usuários conectados%OUT_FIM% %TERMINAL_FIM% Hi! Olha só, não funcionou! É mesmo, não funcionou e não foi por causa das aspas que eu coloquei, mas sim por que eu teria que ter executado o =who | wc -l= antes do =echo=. Para resolver este problema, tenho que priorizar esta segunda parte do comando com o uso de crases, fazendo assim: %TERMINAL_INI% $ echo "Existem `who | wc -l` usuários conectados" %OUT_INI%Existem 8 usuários conectados%OUT_FIM% %TERMINAL_FIM% Para eliminar esse monte de brancos antes do =8= que o =wc -l= produziu, basta tirar as aspas. Assim: %TERMINAL_INI% $ echo Existem `who | wc -l` usuários conectados %OUT_INI%Existem 8 usuários conectados%OUT_FIM% %TERMINAL_FIM% Como eu disse antes, as aspas protegem tudo que esta dentro dos seus limites, da interpretação do _Shell_. Como para o _Shell_ basta um espaço em branco como separador, o monte de espaços será trocado por um único após a retirada das aspas. Antes de falar sobre o uso dos parênteses deixa eu mandar uma rapidinha sobre o uso de ponto-e-vírgula (=;=). Quando estiver no _Shell_, você deve sempre dar um comando em cada linha. Para agrupar comandos em uma mesma linha teremos que separá-los por ponto-e-vírgula. Então: %TERMINAL_INI% $ pwd ; cd /etc; pwd; cd -; pwd %OUT_INI%/home/meudir /etc/ /home/meudir%OUT_FIM% %TERMINAL_FIM% Neste exemplo, listei o nome do diretório corrente com o comando =pwd=, mudei para o diretório =/etc=, novamente listei o nome do diretório e finalmente voltei para o diretório onde estava anteriormente (=cd -=), listando seu nome. Repare que coloquei o ponto-e-vírgula (=;=) de todas as formas possíveis para mostrar que não importa se existe espaços em branco antes ou após este caractere. Finalmente vamos ver o caso dos parênteses. Veja só o caso a seguir, bem parecido com o exemplo anterior: %TERMINAL_INI% $ (pwd ; cd /etc ; pwd;)%OUT_INI% /home/meudir /etc/%OUT_FIM% $ pwd%OUT_INI% /home/meudir%OUT_FIM% %TERMINAL_FIM% - Quequeiiisso minha gente? Eu estava no =/home/meudir=, mudei para o =/etc=, constatei que estava neste diretório com o =pwd= seguinte e quando o agrupamento de comandos terminou, eu vi que continuava no =/home/meudir=, como se eu nunca houvesse saído de lá! - Ih! Será que é tem coisa de mágico aí? - Tá me estranhando, rapaz? Não é nada disso! O interessante do uso de parênteses é que ele invoca um novo _Shell_ para executar os comandos que estão no seu interior. Desta forma, realmente fomos para o diretório =/etc=, porém quando todos os comandos dentro dos parênteses foram executados, o novo _Shell_ que estava no diretório =/etc= morreu e voltamos ao _Shell_ anterior cujo diretório corrente era =/home/meudir=. Faça outros testes usando =cd=, e =ls= para você firmar o conceito. Agora que já conhecemos estes conceitos veja só este exemplo a seguir: %TERMINAL_INI% $ mail suporte << FIM > Ola suporte, hoje as ‘date "+%H:%M"‘ > ocorreu novamente aquele problema > que eu havia reportado por > telefone. Conforme seu pedido > ai vai uma listagem dos arquivos > do diretorio: > ‘ls -l‘ > Abracos a todos. > FIM %TERMINAL_FIM% Finalmente agora temos conhecimento para mostrar o que havíamos conversado sobre __here document__. Os comandos entre crases (=`=) serão priorizados e portanto o _Shell_ os executará antes da instrução =mail=. Quando o suporte receber o _e-mail_, verá que os comandos =date= e =ls= foram executados imediatamente antes do comando =mail=, recebendo então uma fotografia do ambiente no momento em que a correspondência foi enviada. O _prompt_ primário _default_ do _Shell_, como vimos, é o cifrão (=$=), porém o _Shell_ usa o conceito de _prompt_ secundário, ou de continuação de comando, que é enviado para a tela quando há uma quebra de linha e a instrução não terminou. Esse _prompt_, é representado por um sinal de maior (=>=), que vemos precedendo a partir da 2ª linha do exemplo. Para finalizar e bagunçar tudo, devo dizer que existe uma construção mais moderna que vem sendo utilizada como forma de priorização de execução de comandos, tal qual as crases (=`=). São as construções do tipo =$(cmd)=, onde =cmd= é um (ou vários) comando que será(ão) executado(s) com prioridade em seu contexto. Assim sendo, o uso de crases (=`=) ou construções do tipo =$(cmd)= servem para o mesmo fim, porém para quem trabalha com sistemas operacionais de diversos fornecedores (multiplataforma), aconselho o uso das crases, já que o =$(cmd)= não foi portado para todos os sabores de _Shell_. Aqui dentro do Botequim, usarei ambas as formas, indistintamente. Vejamos novamente o exemplo dado para as crases sob esta nova ótica: %TERMINAL_INI% $ echo Existem $(who | wc -l) usuários conectados %OUT_INI%Existem 8 usuários conectados%OUT_FIM% %TERMINAL_FIM% Veja só este caso: %TERMINAL_INI% $ Arqs=ls $ echo $Arqs %OUT_INI%ls%OUT_FIM% %TERMINAL_FIM% Neste exemplo eu fiz uma atribuição (=<nop>==) e executei uma instrução. O que eu queria era que a variável =$Arqs=, recebesse a saída do comando =ls=. Como as instruções de um _script_ são interpretadas de cima para baixo e da esquerda para a direita, a atribuição foi feita antes da execução do =ls=. Para fazer o que desejamos é necessário que eu priorize a execução deste comando em detrimento da atribuição e isto pode ser feito de qualquer uma das maneiras a seguir: %TERMINAL_INI% $ Arqs=`ls` %TERMINAL_FIM% ou: %TERMINAL_INI% $ Arqs=$(ls) %TERMINAL_FIM% Para encerrar este assunto vamos ver só mais um exemplo. Digamos que eu queira colocar dentro da variável =$Arqs= a listagem longa (=ls -l=) de todos os arquivos começados por =arq= e seguidos de um único caractere (=?=). Eu deveria fazer: %TERMINAL_INI% $ Arqs=$(ls -l arq?) %TERMINAL_FIM% ou: %TERMINAL_INI% $ Arqs=`ls -l arq?` %TERMINAL_FIM% Mas veja: %TERMINAL_INI% $ echo $Arqs %OUT_INI%-rw-r--r-- 1 jneves jneves 19 May 24 19:41 arq1 -rw-r--r-- 1 jneves jneves 23 May 24 19:43 arq2 -rw-r--r-- 1 jneves jneves 1866 Jan 22 2003 arql%OUT_FIM% %TERMINAL_FIM% - Pô, saiu tudo embolado! - Pois é cara, como eu já te disse, se você deixar o _Shell_ “ver” os espaços em branco, sempre que houver diversos espaços juntos, eles serão trocados por apenas um. Para que a listagem saia bonitinha, é necessário proteger a variável da interpretação do _Shell_, assim: %TERMINAL_INI% $ echo "$Arqs" %OUT_INI%-rw-r--r-- 1 jneves jneves 19 May 24 19:41 arq1 -rw-r--r-- 1 jneves jneves 23 May 24 19:43 arq2 -rw-r--r-- 1 jneves jneves 1866 Jan 22 2003 arql%OUT_FIM% %TERMINAL_FIM% - Olhe, amigo, vá treinando esses exemplos, porque, quando nos encontrarmos novamente, vou lhe explicar uma série de instruções típicas de programação _Shell_. Tchau! Ahh! Só mais uma coisinha que eu ia esquecendo de lhe dizer. Em _Shell_, o "jogo da velha" (=#=) é usado quando desejamos fazer um comentário. %TERMINAL_INI% $ exit # pede a conta ao garcon :( %TERMINAL_FIM% Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em _Shell_ que mande um e-mail para a nossa <a href="mailto:contato@clavis.com.br?Subject=Curso de Shell com Julio Neves">gerencia de treinamento</a> para informar-se. Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=Dúvidas Papo de Botequim">mim</a>. Valeu!
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r38
<
r37
<
r36
<
r35
<
r34
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r38 - 01 Aug 2009 - 22:32:04 -
BrSalgado
TWikiBar.TWikiBarPapo001 moved from PSLGO.TWikiBarPapo001 on 15 Sep 2005 - 22:26 by
JarbasJunior
-
put it back
TWikiBar
Página Inicial
Últimas alterações
Índice
Procurar
Estatísticas de Uso
Aviso de Atualização
Configurações Gerais
Projeto Gráfico
Mapa do Site
Quem Somos
Registre-se
?
Regras de Formatação
Biblioteca Gráfica
?
Carinhas Gráficas
Webs Wiki-SL
Amadeu
Anapolivre
ArquivoLivre
Arte
BahiaSocial
BeaBa
BibliotecaLivre
Blogs
BrasilDigital
BrasilELivre
BSM
Ccsa
CESL
CoberturaWiki
Cooperativas
Curriculo
DarvinMarosin
DiaD
Dinamicoop
Economia
EconomiaSolidaria
EducacaoLivre
Ekaaty
Emacsbr
ENSL
Fatos
Festival3
Festival4
Flisol
Fmpb
Formatos
Foswikibr
FSM2005
GNOMEBR
GTTemario2004
GTWeb
Guialivre
HDC
Incubus
InkscapeBrasil
Jogos
KdeBR
KSP
LGM
LinuxStokDoc
Livros
Main
Mentores
MHHOB
MinuanoDigital
MoradiaECidadania
OlhosDagua
Olimpo
OLPC
OOPTQ
Papers
PCLivre
PentahoBrasil
Pessoas
Portal
Prefeituras
PSLAL
PSLBA
PSLBancarios
PSLBrasil
PSLGO
PSLMA
PSLMG
PSLMIP
PSLMT
PSLMulheres
PSLPI
PubFisl10
PubFisl7
PubFisl8
PubFisl9
QuilomboDoSopapo
RadioSL
RedeMesh
RedePopular
RobotWars
Sandbox
Saudelivre
Scribus
Sementes
Shakya
SLRJ
SoftwareLivreIrece
SoftwareLivreVS
SoLiSC
SuporteLivre
System
Telecentros
TeseSA
TextoLivre
TV
TWikiBar
TWikiPtbr
UNELivre
UNIMIX
VilaTorres
WebNordeste
WTRD2004
Este Menu
?skin=free
English
Español
Português brasileiro
Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Wiki-SL?
Send feedback