Execução de comandos no terminal, manipulação e organização de arquivos e diretórios, uso de expansões e redirecionamentos, exploração de sistemas de arquivos e camadas de abstração do GNU/Linux, além de monitoramento e medição de desempenho em tarefas práticas."
bash, ls, gcc, e bibliotecas como glibc — tem origem no Projeto GNU. Por isso, quando queremos ser tecnicamente precisos e historicamente justos usamos a expressão GNU/Linux: kernel (Linux) + userland (ferramentas GNU e outros projetos) = sistema operacional completo.
Mencionar Stallman e o Projeto GNU não é reverência vazia: é reconhecer que a filosofia do software livre (e a licença GPL) criou as condições legais e comunitárias para que código pudesse ser estudado, modificado e redistribuído. Essa distinção também evita confusões práticas: o escalonador e a carga de módulos são responsabilidades do kernel; editar um arquivo com nano ou usar grep são tarefas do userland. Saber quem faz o quê facilita aprender administração, programação de sistemas e a interpretação de licenças.
Pense no sistema como um carro: o kernel é o motor; o GNU fornece volante, pedais e painel. Sem ambos, você não dirige — e entender essa analogia ajuda a lembrar por que o nome importa. Historicamente: em 1983 Stallman iniciou o Projeto GNU; em 1991 Linus Torvalds publicou o kernel Linux; a união desses esforços formou o ecossistema que hoje usamos. Reconhecer essa história e compreender a distinção entre kernel e ferramentas do userland é essencial para qualquer pessoa que queira entender, de fato, como sistemas GNU/Linux funcionam.
Considere que você vai implementar uma aplicação que será replicada em 10 diretórios diferentes. Crie os diretórios app1, app2, app3, etc. Dentro de cada diretório crie os subdiretórios src, include e img. Execute os comandos utilizando shell expansions.
app{1..10}: Esta expressão se expande para app1 app2 app3 ... app10.{src,include,img}: Esta expressão se expande para src include img.mkdir -p, que cria diretórios pais se eles não existirem, o shell gera e cria todos os caminhos possíveis (ex: app1/src, app1/include, app1/img, app2/src, etc.) de uma só vez.O comando for possui a sintaxe: for var in intervalo; do comando1; comando2; ...; done. Crie um comando que contenha o comando for e exiba a cada 3 segundos as informações atuais de memória utilizada no sistema.
for que se repete 5 vezes, já que a quantidade de repetições não foi explicitamente determinada. Dentro do laço, usaremos o comando free -h para exibir o uso da memória de forma legível (human-readable) e o comando sleep 3 para pausar a execução por 3 segundos.
for i in {1..5}: Inicia um laço que repetirá 5 vezes.do ... done: Delimita o bloco de comandos a ser executado.echo "--- Verificação #$i ---": Imprime um cabeçalho para cada verificação.free -h: Exibe o uso da memória RAM e swap em formato legível.sleep 3: Pausa o script por 3 segundos.for em C: Para interromper este laço, pressione Ctrl+C. Esta sintaxe for (( ; ; )) é equivalente a while true, mas demonstra a flexibilidade do shell bash. Veja sua implementação na sequência, abaixo.
for (( ; ; )): Sintaxe do laço for estilo C. Os três campos (inicialização; condição; incremento) estão vazios, criando um laço infinito.date '+%F %T': Exibe a data e hora atual no formato YYYY-MM-DD HH:MM:SS (%F = data completa, %T = hora completa).free -h: Mostra o uso de memória em formato legível (human-readable).echo "----": Imprime uma linha separadora para facilitar a visualização.sleep 3: Pausa o script por 3 segundos antes da próxima iteração.contador=1: Inicializa uma variável para numerar as verificações.while true: Cria um laço infinito que executa enquanto a condição for verdadeira (sempre).do ... done: Delimita o bloco de comandos a ser executado repetidamente.echo "--- Verificação #$contador ---": Imprime um cabeçalho numerado para cada verificação.free -h: Exibe o uso da memória RAM e swap em formato legível.((contador++)): Incrementa o contador usando aritmética do bash.sleep 3: Pausa o script por 3 segundos antes da próxima iteração.Ctrl+C.
Navegue até o diretório "/usr/bin", liste o conteúdo do diretório atual e de um diretório inexistente de maneira detalhada, ordenado pelo tamanho, em ordem reversa. Redirecione a saída padrão para o arquivo "~/out" e o erro padrão para o arquivo "~/err". Por fim, exiba o conteúdo dos dois arquivos.
> (ou 1>) para stdout e 2> para stderr.
ls -lSrh . diretorio_inexistente
-l: Formato longo (detalhado) - mostra permissões, proprietário, grupo, tamanho, data de modificação-S: Ordena por tamanho (arquivos maiores primeiro)-r: Ordem reversa (inverte a ordenação - arquivos menores primeiro quando combinado com -S)-h: Formato legível para humanos (mostra tamanhos como 1K, 234M, 2G ao invés de bytes).: Diretório atual (que existe)diretorio_inexistente: Um diretório que não existe> ~/out: Redireciona a listagem bem-sucedida do diretório atual (.) para o arquivo out no diretório home.2> ~/err: Redireciona a mensagem de erro (sobre diretorio_inexistente) para o arquivo err no diretório home.~/out e os erros para ~/err.
Crie, a partir de uma sequência de comandos, um comando chamado ls_log, o qual lista o conteúdo do diretório atual e, caso ocorra algum erro, envia a saída para o arquivo ~/ls.log. Execute o comando ls_log para um diretório inexistente e exiba o conteúdo do arquivo de log.
alias. Um alias é um apelido para um comando ou uma sequência de comandos.
alias ls_log='ls 2> ~/ls.log': Define que, sempre que você digitar ls_log, o shell irá executar o comando ls e redirecionar apenas a saída de erro (2>) para o arquivo ~/ls.log.ls_log __inexistente: Ao executar, o comando ls tenta listar um diretório que não existe, gerando um erro que é capturado pelo log.Crie um comando chamado mkdir_log para criação de diretórios que informe a ocorrência de erros em um arquivo de log. Ele deve salvar a data atual em ~/mkdir.log e criar o diretório da variável $directorio. Se ocorrer um erro, ele deve escrever a data e o erro no log.
mkdir no Bash
mkdir (responsável por criar diretórios), é importante entender como funcionam as saídas do programa. Isso nos permite criar scripts que não apenas executam comandos, mas também registram sucessos e falhas de forma organizada.
ls imprime a listagem de arquivos em stdout.ls listar um diretório inexistente, a mensagem de erro vai para stderr.mkdir
mkdir cria diretórios. Seu comportamento é simples:
variavel=$(comando)
No caso de mkdir, queremos capturar também os erros. Para isso usamos:
erro=$(mkdir "$directorio" 2>&1)
Aqui acontece o seguinte:
2>&1 redireciona stderr (2) para stdout (1).erro.mkdir não imprime nada → erro="" (string vazia).erro="mkdir: cannot create directory ‘/tmp/teste123’: File exists"if [ -z "$erro" ]; then
echo "$(date) - mkdir $directorio" >> ~/mkdir.log
else
echo "$(date) - mkdir $directorio:" >> ~/mkdir.log
echo "$erro" >> ~/mkdir.log
fi
erro estiver vazio → sucesso: apenas registra o comando no log.erro tiver conteúdo → falha: registra o comando e a mensagem de erro.mkdir cria diretórios, mas só fala algo quando dá errado.stderr com 2>&1 nos permite saber quando houve problema.Considere os comandos head -n n e tail -n n, os quais retornam os n primeiros ou n últimos itens da entrada padrão. Crie os diretórios 5size, 20size, 5date, 20date no diretório home do usuário. Liste os 5 maiores e depois os 20 maiores arquivos de /bin e copie-os para 5size e 20size, respectivamente. Liste os 5 arquivos mais recentes e depois os 20 arquivos mais recentes de /bin e copie-os para 5date e 20date. Execute os comandos apenas utilizando ls, head, tail, cp e cd.
/bin) primeiro. Isso simplifica o comando cp, pois não precisamos manipular os caminhos dos arquivos.
cd /bin: O passo crucial. Ao entrarmos no diretório, os comandos subsequentes operam diretamente nos arquivos de lá.ls -S | head -n 5: Lista os arquivos por tamanho (maior primeiro) e seleciona os 5 primeiros.cp $(...) ~/5size/: A construção $(...) executa o comando interno e a saída (a lista de nomes de arquivos) é usada como argumento para o cp. Como já estamos em /bin, não precisamos nos preocupar com o caminho completo dos arquivos.ls -t: É usado para ordenar os arquivos por data de modificação (mais recentes primeiro).tr ou xargs para criar soluções mais diretas e robustas, sem a necessidade de usar cd. Elas são ideais para scripts, pois não alteram o diretório atual.
O comando tr (translate) substitui as quebras de linha da saída do ls por espaços, criando uma lista de argumentos para o cp.
xargs é a ferramenta padrão para esta tarefa, pois constrói e executa comandos a partir da entrada padrão. É mais seguro porque lida corretamente com nomes de arquivos que possam conter espaços ou caracteres especiais.
No diretório home: (i) crie os diretórios A, B, C, D e E; (ii) liste todos os arquivos que iniciam com "a", "b", "c", "d" e "e" em /bin e redirecione a saída de cada listagem para os arquivos correspondentes (A/a.txt, B/b.txt, etc.).
for.
mkdir {A,B,C,D,E}: Usa a expansão de chaves para criar os 5 diretórios de uma vez.for letra in a b c d e; do ... done: Itera sobre cada letra.dir_letra=$(...): Converte a letra minúscula para maiúscula para encontrar o nome do diretório.ls /bin/${letra}*: O asterisco * é um caractere curinga (globbing) que significa "qualquer sequência de caracteres". Portanto, a* encontra todos os arquivos que começam com "a".> ${dir_letra}/${letra}.txt: O redirecionador que cria (ou sobrescreve) o arquivo de destino com a saída do comando.No diretório home, crie os arquivos "file 0" contendo "0", "file 1" contendo "1" e "file 2" contendo "2". A seguir, anexe o conteúdo de cada arquivo para o arquivo "file 0 1 2".
comando > arquivo: Cria um novo arquivo (ou zera um existente) e escreve a saída do comando nele.comando >> arquivo: Adiciona a saída do comando ao final do arquivo, sem apagar seu conteúdo anterior.cat "file 0" "file 1" "file 2" > "file 0 1 2" é uma forma curta e eficiente de concatenar todos os arquivos de uma vez.Identifique as camadas de abstração de um Sistema Operacional GNU/Linux. Para cada camada, liste um comando ou funcionalidade que a represente e explique brevemente como ela é usada na prática.
lspci, lsusb. O hardware é representado em /dev e /sys.lspci lista os dispositivos conectados ao barramento PCI, permitindo ver qual hardware (placa de vídeo, de rede) está fisicamente presente e reconhecido.uname -r (versão do kernel), dmesg (mensagens do kernel)./dev (ex: /dev/sdb1).bash, zsh. Qualquer comando como ls, cd, pwd.ls -l, o Shell interpreta o comando, localiza o programa /bin/ls e solicita ao Kernel que o execute para obter as informações.grep, cp, Firefox, LibreOffice.Explique o papel do gerenciamento de processos, gerenciamento de memória, drivers de dispositivos e chamadas de sistema no GNU/Linux. Em seguida, descreva um cenário de uso prático para cada um.
ps aux para ver os processos.free -h para ver o status.uvcvideo), e a partir daí sabe como se comunicar com a câmera. Aplicações como o Zoom podem então usá-la.cat meu_arquivo.txt. O programa cat faz chamadas de sistema como open(), read(), write() e close() para pedir ao Kernel que abra, leia, escreva na tela e feche o arquivo. Use strace cat meu_arquivo.txt para ver as chamadas.Descreva como o Linux gerencia dispositivos de entrada e saída (I/O). Identifique e explique, com exemplos, cada um dos quatro tipos de dispositivos no Linux.
O gerenciamento de I/O no Linux é unificado sob o princípio "tudo é um arquivo". A maioria dos dispositivos é representada como um arquivo especial em /dev, permitindo que programas interajam com o hardware lendo e escrevendo nesses arquivos.
/dev/hda), SSDs (/dev/sda), NVMes (/dev/nvme0n1), Pendrives (/dev/sdc), etc.../dev/tty1), Portas seriais (/dev/ttyS0), Mouses (/dev/input/mice)./dev/null (buraco negro), /dev/zero (fonte de caracteres nulos), /dev/random (fonte de números aleatórios)./dev, mas gerenciados por uma API separada (sockets).eth0), Adaptador Wi-Fi (wlan0), Interface de Loopback (lo).Use o comando ls -l para listar de forma detalhada um dispositivo de bloco, um dispositivo de caractere e um pipe nomeado em algum lugar do sistema de arquivos. Indique os caminhos usados.
ls -l revela o tipo de arquivo no primeiro caractere de sua saída: b para dispositivo de bloco, c para dispositivo de caractere, e p para pipe nomeado (FIFO).
b no início (brw...) indica que é um dispositivo de bloco.c no início (crw...) indica que é um dispositivo de caractere.p no início (prw...) indica que é um pipe nomeado.Como podem imaginar (e constatar), Pipes nomeados são usados para comunicação entre processos. Um processo pode escrever dados no pipe, enquanto outro lê esses dados, funcionando como um canal de comunicação. 🚀 É simples, mas vamos destrinchar esse tal de mkfifo.
prw-...) mostra que é um pipe nomeado.& para rodar em paralelo):echo "teste" | grep t).meu_pipe).mkfifo nome → cria um pipe nomeado (FIFO).Descreva a função do sistema de arquivos sysfs em sistemas GNU/Linux. Explore o diretório /sys para encontrar exemplos práticos de como essa estrutura ajuda na comunicação com o hardware.
O sysfs é um sistema de arquivos virtual montado em /sys, criado dinamicamente na memória pelo Kernel. Sua função principal é exportar uma visão da árvore de dispositivos do Kernel para o espaço do usuário (userland), permitindo visualizar e, em alguns casos, modificar parâmetros do hardware e drivers em tempo real. Diferente do /proc (que foca em informações de processos e do estado geral do kernel), o /sys é organizado em torno da topologia do hardware, com estruturas para dispositivos, classes, barramentos e drivers.
udev e systemd usam o /sys extensivamente para detectar e configurar hardware automaticamente quando um dispositivo é conectado ou o sistema é inicializado.
Podemos listar os diretórios principais para entender a organização do sysfs.
Cada dispositivo expõe seus atributos como arquivos de texto simples.
Alguns arquivos no /sys permitem escrita, possibilitando a alteração de parâmetros do driver em tempo real.
/sys modifica diretamente o comportamento do Kernel e dos drivers. Faça isso com cuidado, pois uma configuração incorreta pode causar instabilidade no sistema. Por exemplo, o comando echo on > /sys/bus/usb/devices/usb1/power/control poderia ser usado para desabilitar o auto-suspend de um dispositivo USB.
Crie dois arquivos de 10MB de tamanho chamados random_high_quality.txt e nulo.txt e utilize o comando time para medir o tempo de execução para gerar cada arquivo. O primeiro deve conter dados aleatórios de alta qualidade, e o último apenas valores nulos (\0).
dd para ler de uma fonte e escrever em um destino, e o comando time como prefixo para medir o desempenho.
/dev/random pode ser extremamente lenta ou até mesmo falhar. Isso é esperado e será explicado na próxima questão.
Considere o exercício 14 e responda. Qual geração de arquivo foi mais rápida? Por que? Justifique sua resposta.
nulo.txt a partir de /dev/zero foi incomparavelmente mais rápida. A razão está na natureza e complexidade das fontes de dados.
\0)./dev/random bloqueia (pausa) até coletar mais entropia, tornando o processo muito lento, especialmente em sistemas com pouca atividade./dev/urandom é preferível. Ele é um meio-termo: suficientemente seguro e não bloqueia quando o pool de entropia se esgota.
Crie uma imagem de disco de 1GB, crie duas partições, formate-as (ext4, msdos), monte-as, crie um arquivo em cada, verifique o espaço e desmonte.
sudo).