Subshells avançados de Linux com exemplos

Subshells avançados de Linux com exemplos

Se você ler nossas subs -grandes do Linux anteriores para iniciantes com exemplos de exemplos ou já tiver experiência com sub -explosões, você sabe que as subs -grandes são uma maneira poderosa de manipular os comandos do Bash embutido e de maneira sensível ao contexto.

Neste tutorial, você aprenderá:

  • Como criar comandos de subshell mais avançados
  • Onde você pode empregar sub -explosões mais avançadas em seu próprio código
  • Exemplos de comandos de subshell mais avançados
Subshells avançados de Linux com exemplos

Requisitos de software e convenções usadas

Requisitos de software e convenções de linha de comando Linux
Categoria Requisitos, convenções ou versão de software usada
Sistema Independente da distribuição Linux
Programas Linha de comando Bash, sistema baseado em Linux
Outro Qualquer utilidade que não esteja incluída no shell bash por padrão pode ser instalada usando sudo apt-get install utility-name (ou yum em vez de apt-get)
Convenções # - requer que o Linux -Commands seja executado com privilégios de raiz diretamente como usuário root ou por uso de sudo comando
$-exige que o Linux-Commands seja executado como um usuário não privilegiado regular

Exemplo 1: Arquivos de contagem

$ se [$ (ls [a -z]* 2>/dev/null | wc -l) -gt 0]; Então o eco "encontrou uma ou mais ocorrências de arquivos [a-z]*!"; Fi 


Aqui temos um se declaração com o seu primeiro valor de comparação, uma subshell. Isso funciona bem e oferece uma grande quantidade de flexibilidade quando se trata de escrever se declarações. É diferente que o binário (verdadeiro ou falso) como operação de por exemplo Se Grep -q 'Search_term' ./docfile.TXT declaração. Em vez disso, é avaliado por si só como uma comparação padrão (combinada com o maior que eu zero -GT 0 cláusula).

A subshell tenta os arquivos de lista de diretórios nomeados [a-z]*, eu.e. arquivos começando com pelo menos uma letra no a-z alcance, seguido por qualquer personagem subsequente. É seguro de erro adicionando 2>/dev/nulo - eu.e. Qualquer erro exibido (em stderr - a saída de erro padrão, significada pelo 2) será redirecionado > para /dev/null - eu.e. O dispositivo nulo Linux - e, portanto, ignorado.

Finalmente passamos a entrada do LS para wc -l que contarão para nós quantas linhas (ou neste caso, arquivos) foram vistos. Se o resultado foi mais do que 0, a nota informativa será mostrada.

Observe como o contexto em que o subshell está operando é variado. Em primeiro lugar, neste caso, a subshell está trabalhando dentro do diretório de trabalho atual (i.e. $ PWD) que é notavelmente também o padrão eu.e. Subshells por padrão Iniciar com seu próprio ambiente PWD definido para o diretório de trabalho atual. Em segundo lugar, a subshell está trabalhando dentro do contexto de um se declaração.

Nenhuma saída é gerada por este comando, pois está sendo executado dentro de um diretório vazio. No entanto, observe que o fato de que nenhuma saída é gerada também significa que nossa supressão de erros está funcionando. Vamos verificar isso:

$ se [$ (ls [a -z]* | wc -l) -gt 0]; Então o eco "encontrou uma ou mais ocorrências de arquivos [a-z]*!"; fi ls: não pode acessar '[a-z]*': nenhum arquivo ou diretório 

Podemos ver como a remoção da supressão de erro funcionou no exemplo anterior. Vamos criar um arquivo e ver como o nosso liner se executa:

$ touch a $ se [$ (ls [a -z]* 2>/dev/null | wc -l) -gt 0]; Então o eco "encontrou uma ou mais ocorrências de arquivos [a-z]*!"; Fi encontrou uma ou mais ocorrências de arquivos [a-z]*! 


Ótimo, parece que nosso script de uma linha tem um bom desempenho. Vamos adicione um arquivo secundário e ver se podemos melhorar a mensagem

$ touch b $ se [$ (ls [a -z]* 2>/dev/null | wc -l) -gt 0]; Então o eco "encontrou uma ou mais ocorrências de arquivos [a-z]*!"; Fi encontrou uma ou mais ocorrências de arquivos [a-z]*! $ se [$ (ls [a -z]* 2>/dev/null | wc -l) -gt 0]; Então o eco "encontrou exatamente $ (ls [a-z]* 2>/dev/null | wc -l) ocorrências de [a-z]* arquivos!"; Fi encontrou exatamente 2 ocorrências de arquivos [a-z]*! 

Aqui vemos que a adição de um segundo arquivo (por toque b) não faz nenhuma diferença (como visto no primeiro se comando), a menos que alteremos a saída para realmente relatar quantos arquivos foram encontrados inserindo uma subshell secundária na saída.

No entanto, isso não é codificado de maneira ideal; Nesse caso, duas sub -explosões requerem execução (o custo de uma criação de subshell é muito mínimo, mas se você tiver muitas sub -rotas sendo criadas em alta frequência, o custo é importante), e a listagem diretamente é solicitada duas vezes (gerando E/S adicional e E/S e desacelerando nosso código para a velocidade do subsistema de E/S e o tipo de disco usado). Vamos colocar isso em uma variável:

$ Count = "$ (ls [a -z]* 2>/dev/null | wc -l)"; se [$ count -gt 0]; Então o eco "encontrou exatamente $ count ocorrências de [a-z]* arquivos!"; Fi encontrou exatamente 2 ocorrências de arquivos [a-z]*! 

Ótimo. Este é o código mais ideal; Uma única subshell é usada e o resultado é armazenado em uma variável que é usada duas vezes, e apenas uma única recuperação de listagem de diretório de disco é necessária. Observe também que esta solução pode ser mais segura por threads.

Por exemplo, no se Declaração que teve duas sub-grandes, se, no tempo entre a execução dessas subshells, um terceiro arquivo foi criado, o resultado pode parecer assim: Encontrou exatamente 3 ocorrências de arquivos [a-z]*! enquanto o primeiro se declaração (usando o primeiro subshell) realmente se qualificou em Se 2 -gt 0 - eu.e. 2. Faria pouca diferença neste caso, mas você pode ver como em alguma codificação isso pode se tornar muito importante.

Exemplo 2: Subshells para cálculo

$ touch z $ echo $ [$ (data + %s) - $ (stat -c %z ./z)] 1 $ echo $ [$ (data + %s) - $ (stat -c %z ./z)] 5 

Aqui criamos um arquivo, ou seja, z, e posteriormente descobriu a idade do arquivo em segundos usando o segundo comando. Alguns segundos depois, executamos o comando novamente e podemos ver que o arquivo agora tem 5 segundos de idade.

O data +%s O comando nos dá o tempo atual em segundos desde a Epoch (1970-01-01 UTC) e stat -c %z nos dá os segundos desde a época do arquivo que foi criado anteriormente e agora referenciado aqui como ./z, Então, tudo o que precisamos posteriormente é subtrair esses dois um do outro. Colocamos o data +%s Primeiro, pois esse é o número mais alto (o horário atual) e, portanto, calcule corretamente o deslocamento em segundos.

O -c opção para Estado simplesmente indica que queremos uma formatação de saída específica, neste caso %Z, Ou, em outras palavras, o tempo desde a época. Para data A sintaxe para a mesma ideia é +%s, embora em conexão com o tempo atual e não esteja relacionado a um arquivo específico.

Exemplo 3: Subshells dentro de sed e outras ferramentas

$ echo '0'> a $ sed -i "s | 0 | $ (whoami) |" ./A $ CAT A ROEL 


Como você pode ver, podemos usar uma subshell em quase qualquer comando que executamos na linha de comando.

Nesse caso, criamos um arquivo a com conteúdo como 0 e posteriormente em linha substitua o 0 para $ (whoami) que, quando a subshell é executada como o comando está sendo analisada, substituirá o nome de usuário Roel. Cuidado para não usar citações únicas, pois isso tornará a sub -Shell inativa porque a string será interpretada como texto literal:

$ echo '0'> a $ sed -i 's | 0 | $ (whoami) |' ./a $ cat a $ (whoami) 

Observe aqui que o sed Sintaxe Ativada (S | 0 |… |) ainda funciona corretamente (!), enquanto a funcionalidade da subshell da Bash $ () nao fiz!

Exemplo 4: Usando avaliar e um loop

$ Loops = 3 $ echo 1… $ loops 1… 3 $ avaliar echo 1… $ loops 1 2 3 $ para i em $ (echo 1… $ loops); eco "$ i"; feito 1… 3 $ para i em $ (avaliar eco 1… $ loops); eco "$ i"; feito 1 2 3 

Este exemplo, embora não seja a maneira ideal de executar um direto para Loop, mostra -nos algumas maneiras de integrar sub -grandes, mesmo dentro de loops. Nós usamos o aval declaração para processar o 1… 3 texto em 1 2 3 que pode ser usado diretamente dentro do para Cláusula de repetição de loop.

Às vezes, o uso de sub-grandes e fornecendo informações em linha em linha através de sub-shells nem sempre é evidente e pode exigir alguns testes, ajustes e ajustes finos antes que as sub-capítulos sejam executadas conforme esperado. Isso é normal e muito alinhado com a codificação de bash normal.

Conclusão

Neste artigo, exploramos alguns exemplos mais aprofundados e avançados de usar subs-grandes em Bash. O poder das subshells permitirá que você transforme a maioria dos scripts de uma linha em versões muito mais poderosas, sem mencionar a possibilidade de usá-las dentro de seus scripts. Quando você começa a explorar subs -grandes e encontra algumas maneiras legais de usá -las, poste -as abaixo nos comentários!

Aproveitar!

Tutoriais do Linux relacionados:

  • Coisas para instalar no Ubuntu 20.04
  • Coisas para fazer depois de instalar o Ubuntu 20.04 fossa focal linux
  • Subshells Linux para iniciantes com exemplos
  • Uma introdução à automação, ferramentas e técnicas do Linux
  • Como usar as sub -mais de bases dentro das declarações if if
  • Coisas para fazer depois de instalar o Ubuntu 22.04 Jellyfish…
  • Comandos Linux: os 20 comandos mais importantes que você precisa para…
  • Comandos básicos do Linux
  • Download do Linux
  • Instale Arch Linux na estação de trabalho VMware