GNU/Linux

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."

Por Fábio Linhares • Instituto Infnet

Aviso inicial — crédito a quem merece

Antes de qualquer coisa: Linux não é o sistema por completo. Apesar disso, é comum ouvir “Linux” para nomear o sistema inteiro. Contudo, isso acaba apagando — por desconhecimento ou descaso — contribuições fundamentais do Projeto GNU, de Richard Stallman e das comunidades que construíram as ferramentas que você usa no dia a dia. Entender essa diferença é útil: não se trata apenas de nomenclatura, mas de reconhecer responsabilidades técnicas (o que roda no kernel versus o que roda no userland), implicações de licenças e a história por trás das ferramentas. Tecnicamente, Linux é o kernel — o núcleo que conversa com o hardware, agenda processos, gerencia memória e carrega drivers. Sozinho, o kernel é potente, porém incompleto: é preciso um conjunto de utilitários, bibliotecas e ferramentas para transformar esse núcleo em um sistema utilizável. Grande parte desse userland — programas como 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.
EXERCÍCIO 01
Criação de Diretórios com Shell Expansions
Objetivo: Criar uma estrutura de diretórios replicada usando expansões de chaves.

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.

O Shell (como o Bash) possui um recurso chamado "expansão de chaves" (brace expansion) que permite gerar strings arbitrárias. Podemos usar isso para criar todos os diretórios e subdiretórios com um único comando.
hacker@matrix:~$ mkdir -p app{1..10}/{src,include,img}
Como funciona:
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.
Combinando os dois com o comando 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.
EXERCÍCIO 02
Monitoramento de Memória com `for`
Objetivo: Criar um loop para exibir o uso de memória a cada 3 segundos.

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.

Para esta tarefa criaremos um laço 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.
hacker@matrix:~$ for i in {1..5}; do echo "--- Verificação #$i ---"; free -h; sleep 3; done
--- Verificação #1 --- total used free shared buff/cache available Mem: 7.7Gi 1.2Gi 5.8Gi 1.0Mi 825Mi 6.4Gi Swap: 2.0Gi 0B 2.0Gi --- Verificação #2 --- ... (saída se repete a cada 3 segundos) ...
Explicação dos comandos:
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.
Para um monitoramento contínuo (sem fim), poderíamos "alternativamente" usar a sintaxe especial do 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.
hacker@matrix:~$ for (( ; ; )); do date '+%F %T'; free -h; echo "----"; sleep 3; done
2025-01-15 14:23:45 total used free shared buff/cache available Mem: 7.7Gi 1.2Gi 5.8Gi 1.0Mi 825Mi 6.4Gi Swap: 2.0Gi 0B 2.0Gi ---- 2025-01-15 14:23:48 total used free shared buff/cache available Mem: 7.7Gi 1.3Gi 5.7Gi 1.0Mi 830Mi 6.3Gi Swap: 2.0Gi 0B 2.0Gi ---- ... (continua indefinidamente até Ctrl+C) ...
hacker@matrix:~$ contador=1; while true; do echo "--- Verificação #$contador ---"; free -h; ((contador++)); sleep 3; done
--- Verificação #1 --- total used free shared buff/cache available Mem: 7.7Gi 1.2Gi 5.8Gi 1.0Mi 825Mi 6.4Gi Swap: 2.0Gi 0B 2.0Gi --- Verificação #2 --- total used free shared buff/cache available Mem: 7.7Gi 1.3Gi 5.7Gi 1.0Mi 830Mi 6.3Gi Swap: 2.0Gi 0B 2.0Gi --- Verificação #3 --- ... (continua indefinidamente até Ctrl+C) ...
Explicação dos comandos: for do C
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.
Explicação dos comandos: while
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.
Lembre-se: para interromper qualquer um desses laços infinitos, ou não, pressione Ctrl+C.
EXERCÍCIO 03
Redirecionamento de Saídas Padrão e de Erro
Objetivo: Separar saídas bem-sucedidas e erros em arquivos diferentes.

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.

Em GNU/Linux, existem dois "canais" de saída principais: Saída Padrão (stdout) para resultados esperados e Erro Padrão (stderr) para mensagens de erro. Podemos redirecioná-los usando > (ou 1>) para stdout e 2> para stderr.
hacker@matrix:~$ cd /usr/bin
hacker@matrix:/usr/bin$ ls -lSrh . diretorio_inexistente > ~/out 2> ~/err
hacker@matrix:/usr/bin$ echo "--- Conteúdo de ~/out (Saída Padrão) ---" && cat ~/out | head
--- Conteúdo de ~/out (Saída Padrão) --- total 1.2G -rwxr-xr-x 1 root root 0 Jan 1 1970 [ ... (lista de arquivos de /usr/bin) ...
hacker@matrix:/usr/bin$ echo -e "\n--- Conteúdo de ~/err (Erro Padrão) ---" && cat ~/err
--- Conteúdo de ~/err (Erro Padrão) --- ls: cannot access 'diretorio_inexistente': No such file or directory
Explicação:
Comando: ls -lSrh . diretorio_inexistente

Quebra das opções:
  • -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)
Argumentos:
  • .: 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.
Resultado: O comando listará o conteúdo do diretório atual ordenado por tamanho (menor para maior) em formato detalhado e legível. A saída normal vai para ~/out e os erros para ~/err.
EXERCÍCIO 04
Criação de um Comando Personalizado com Log de Erros
Objetivo: Criar um alias para listar diretórios e registrar erros.

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.

A forma mais simples de criar um novo "comando" para uso na sessão atual é através de um alias. Um alias é um apelido para um comando ou uma sequência de comandos.
hacker@matrix:~$ alias ls_log='ls 2> ~/ls.log'
hacker@matrix:~$ ls_log __inexistente
hacker@matrix:~$ echo "--- Conteúdo de ~/ls.log ---" && cat ~/ls.log
--- Conteúdo de ~/ls.log --- ls: cannot access '__inexistente': No such file or directory
Como funciona:
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.
Lembre-se: aliases criados como os da resposta acima são temporários! Eles funcionam apenas na sessão atual do shell. Para torná-los permanentes, adicione o comando `alias` ao arquivo `~/.bashrc` (ou `~/.zshrc` se usar zsh). Alternativamente, crie um script executável em `/usr/local/bin/` para disponibilizar o comando globalmente no sistema.
EXERCÍCIO 05
Comando Personalizado com Log Avançado
Objetivo: Criar uma função de shell para criar diretórios com log de sucesso e erro.

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.

Esta tarefa é mais complexa e é melhor resolvida com uma função de shell, que é mais poderosa que um alias e permite lógica condicional.
hacker@matrix:~$ mkdir_log() { local erro erro=$(mkdir "$directorio" 2>&1) if [ -z "$erro" ]; then echo "$(date) - mkdir $directorio" >> ~/mkdir.log else echo "$(date) - mkdir $directorio:" >> ~/mkdir.log echo "$erro" >> ~/mkdir.log fi }
Cenário 1: Execução com SUCESSO
hacker@matrix:~$ rm -f ~/mkdir.log
hacker@matrix:~$ export directorio=~/meu_novo_app
hacker@matrix:~$ mkdir_log
hacker@matrix:~$ cat ~/mkdir.log
Sat Aug 31 10:15:20 -03 2025 - mkdir /home/hacker/meu_novo_app
Cenário 2: Execução com ERRO (diretório já existe)
hacker@matrix:~$ mkdir_log
hacker@matrix:~$ cat ~/mkdir.log
Sat Aug 31 10:15:20 -03 2025 - mkdir /home/hacker/meu_novo_app Sat Aug 31 10:15:45 -03 2025 - mkdir /home/hacker/meu_novo_app: mkdir: cannot create directory ‘/home/hacker/meu_novo_app’: File exists
Acho que vale a pena uma explicação[zinha]...
📂 Como funciona a captura de erros com mkdir no Bash

Quando usamos comandos no GNU/Linux, como o 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.
🔎 Saídas de um comando
Todo comando no GNU/Linux pode escrever em dois canais principais:
  1. stdout (standard output ou saída padrão)
    • Onde vai a saída “normal” do programa.
    • Exemplo: ls imprime a listagem de arquivos em stdout.
  2. stderr (standard error ou saída de erros)
    • Onde vão as mensagens de erro.
    • Exemplo: se você pedir para ls listar um diretório inexistente, a mensagem de erro vai para stderr.
📌 O caso do mkdir
O comando mkdir cria diretórios. Seu comportamento é simples:
  • Se funcionar: ele cria o diretório em silêncio.
    • Não imprime nada em stdout.
    • Não imprime nada em stderr.
  • Se falhar: ele envia uma mensagem explicando o erro para stderr.
    • Exemplo: tentar criar um diretório que já existe.
🛠️ Capturando mensagens de erro
Podemos capturar a saída de um comando dentro de uma variável usando a sintaxe:
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).
  • Assim, stdout + stderr vão para dentro da variável erro.
📖 Interpretando o resultado
Agora, a lógica é simples:
  • Se não houve erro, o mkdir não imprime nada → erro="" (string vazia).
  • Se houve erro, a mensagem do erro aparece dentro da variável → erro="mkdir: cannot create directory ‘/tmp/teste123’: File exists"
✅ Colocando em prática
Podemos usar esse comportamento em scripts para registrar o que aconteceu. Por exemplo:
if [ -z "$erro" ]; then
  echo "$(date) - mkdir $directorio" >> ~/mkdir.log
else
  echo "$(date) - mkdir $directorio:" >> ~/mkdir.log
  echo "$erro" >> ~/mkdir.log
fi
  • Se erro estiver vazio → sucesso: apenas registra o comando no log.
  • Se erro tiver conteúdo → falha: registra o comando e a mensagem de erro.
🎯 Em resumo
  • mkdir cria diretórios, mas só fala algo quando dá errado.
  • Capturar stderr com 2>&1 nos permite saber quando houve problema.
  • Ao testar se a variável está vazia ou não, conseguimos diferenciar sucesso de erro e registrar tudo num log.

Essa técnica é muito útil para criar scripts robustos que não apenas executam, mas também documentam seu próprio funcionamento.
EXERCÍCIO 06
Manipulando Arquivos com `head` e `tail`
Objetivo: Listar e copiar arquivos com base em tamanho e data, usando um conjunto restrito de comandos.

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.

A solução mais elegante que respeita a restrição de comandos é navegar para o diretório de origem (/bin) primeiro. Isso simplifica o comando cp, pois não precisamos manipular os caminhos dos arquivos.
# 1. Navegar para o diretório home e criar os diretórios de destino
hacker@matrix:~$ cd ~
hacker@matrix:~$ mkdir -p 5size 20size 5date 20date
# 2. Navegar para o diretório /bin
hacker@matrix:~$ cd /bin
# 3. Copiar os arquivos baseados em TAMANHO
hacker@matrix:/bin$ cp $(ls -S | head -n 5) ~/5size/
hacker@matrix:/bin$ cp $(ls -S | head -n 20) ~/20size/
# 4. Copiar os arquivos baseados em DATA
hacker@matrix:/bin$ cp $(ls -t | head -n 5) ~/5date/
hacker@matrix:/bin$ cp $(ls -t | head -n 20) ~/20date/
# 5. Voltar para o diretório home
hacker@matrix:/bin$ cd ~
Explicação da Solução:
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).
Soluções Alternativas (Mais Robustas)

Se a restrição de comandos fosse relaxada, poderíamos usar ferramentas como 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.
Alternativa 1: Usando `tr`

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.

# Copiando os 5 maiores arquivos com 'tr'
hacker@matrix:~$ cp /bin/$(ls -S /bin | head -n 5 | tr '\n' ' ') ~/5size/ 2>/dev/null
Alternativa 2: Usando `xargs` (A Mais Segura)

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.

# Copiando os 5 maiores arquivos com 'xargs'
hacker@matrix:~$ ls -S /bin | head -n 5 | xargs -I {} cp /bin/{} ~/5size/
EXERCÍCIO 07
Expansões, Globbing e Redirecionamento em Massa
Objetivo: Automatizar a criação de diretórios e o redirecionamento de listagens de arquivos.

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.).

Podemos fazer isso de forma manual e repetitiva, ou de uma forma mais elegante e eficiente com um laço for.
Solução com Laço `for` (Avançada e Eficiente)
hacker@matrix:~$ cd ~ && mkdir {A,B,C,D,E}
hacker@matrix:~$ for letra in a b c d e; do dir_letra=$(echo $letra | tr '[:lower:]' '[:upper:]') ls /bin/${letra}* > ${dir_letra}/${letra}.txt done
Explicação:
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.
EXERCÍCIO 08
Criação e Concatenação de Arquivos
Objetivo: Criar múltiplos arquivos e concatenar seu conteúdo em um único arquivo.

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".

É importante usar aspas ao lidar com nomes de arquivos que contêm espaços.
hacker@matrix:~$ cd ~
hacker@matrix:~$ echo "0" > "file 0"
hacker@matrix:~$ echo "1" > "file 1"
hacker@matrix:~$ echo "2" > "file 2"
hacker@matrix:~$ cat "file 0" "file 1" "file 2" > "file 0 1 2"
hacker@matrix:~$ cat "file 0 1 2"
0 1 2
Diferença entre `>` e `>>`:
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.
No exemplo, cat "file 0" "file 1" "file 2" > "file 0 1 2" é uma forma curta e eficiente de concatenar todos os arquivos de uma vez.
EXERCÍCIO 09
Camadas de Abstração do GNU/Linux
Objetivo: Identificar e explicar as camadas de abstração de um SO GNU/Linux com exemplos.

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.

1. Hardware
O que é: A camada física (CPU, RAM, discos, etc.).
Representação/Comando: lspci, lsusb. O hardware é representado em /dev e /sys.
Uso Prático: O comando lspci lista os dispositivos conectados ao barramento PCI, permitindo ver qual hardware (placa de vídeo, de rede) está fisicamente presente e reconhecido.
2. Kernel Linux
O que é: O núcleo do SO. Gerencia o hardware, aloca recursos e faz a ponte entre hardware e software.
Representação/Comando: uname -r (versão do kernel), dmesg (mensagens do kernel).
Uso Prático: Quando você insere um pendrive, o Kernel detecta o hardware, usa o driver apropriado e o torna disponível como um arquivo em /dev (ex: /dev/sdb1).
3. Shell (Intérprete de Comandos)
O que é: A interface que permite interagir com o Kernel.
Representação/Comando: bash, zsh. Qualquer comando como ls, cd, pwd.
Uso Prático: Ao digitar ls -l, o Shell interpreta o comando, localiza o programa /bin/ls e solicita ao Kernel que o execute para obter as informações.
4. Aplicações e Utilitários (Userland)
O que é: Programas que o usuário executa para realizar tarefas.
Representação/Comando: grep, cp, Firefox, LibreOffice.
Uso Prático: O Firefox não acessa a placa de rede diretamente. Ele pede ao Kernel (através de chamadas de sistema) para enviar e receber dados pela rede.
EXERCÍCIO 10
Papel dos Componentes do Kernel
Objetivo: Explicar os papéis de componentes chave do Kernel com cenários práticos.

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.

1. Gerenciamento de Processos
Papel: Criar, agendar e finalizar processos, garantindo que rodem de forma concorrente e isolada.
Cenário Prático: Você abre um editor de texto e compila um programa ao mesmo tempo. O escalonador do Kernel alterna o uso da CPU rapidamente entre os dois, para que o editor responda à digitação e o compilador continue trabalhando. Use ps aux para ver os processos.
2. Gerenciamento de Memória
Papel: Alocar e liberar RAM para processos, e gerenciar a memória virtual (usando swap).
Cenário Prático: Você edita uma imagem grande no GIMP. O Kernel aloca RAM para ele. Se a RAM acabar, o Kernel move blocos de memória de programas inativos para o swap no disco, liberando RAM para o GIMP. Use free -h para ver o status.
3. Drivers de Dispositivos
Papel: Atuar como um tradutor entre o Kernel e um dispositivo de hardware específico.
Cenário Prático: Você conecta uma webcam. O Kernel detecta o dispositivo, carrega o driver correspondente (ex: uvcvideo), e a partir daí sabe como se comunicar com a câmera. Aplicações como o Zoom podem então usá-la.
4. Chamadas de Sistema (System Calls)
Papel: A interface de comunicação entre os programas do usuário e o Kernel.
Cenário Prático: Você executa 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.
EXERCÍCIO 11
Gerenciamento de Dispositivos de I/O
Objetivo: Descrever como o GNU/Linux gerencia I/O e os tipos de dispositivos.

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.

1. Dispositivos de Bloco (Block Devices)
Explicação: Transferem dados em blocos de tamanho fixo e permitem acesso aleatório (ler/escrever em qualquer bloco). Ideais para sistemas de arquivos.
Exemplos: Discos Rígidos (/dev/hda), SSDs (/dev/sda), NVMes (/dev/nvme0n1), Pendrives (/dev/sdc), etc...
2. Dispositivos de Caractere (Character Devices)
Explicação: Transferem dados como um fluxo sequencial de bytes, um por um. Geralmente não permitem acesso aleatório.
Exemplos: Terminais (/dev/tty1), Portas seriais (/dev/ttyS0), Mouses (/dev/input/mice).
3. Pseudo-dispositivos (Pseudo-devices)
Explicação: Dispositivos virtuais implementados em software, sem hardware físico correspondente.
Exemplos: /dev/null (buraco negro), /dev/zero (fonte de caracteres nulos), /dev/random (fonte de números aleatórios).
4. Dispositivos de Rede (Network Devices)
Explicação: Uma exceção à regra "tudo é um arquivo". Não são representados em /dev, mas gerenciados por uma API separada (sockets).
Exemplos: Placa Ethernet (eth0), Adaptador Wi-Fi (wlan0), Interface de Loopback (lo).
EXERCÍCIO 12
Listando Tipos de Dispositivos com `ls` e Pipe Nomeado
Objetivo: Usar `ls -l` para identificar dispositivos de bloco, de caractere e pipes nomeados.

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.

O comando 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).
Dispositivo de Bloco (ex: primeiro disco rígido)
hacker@matrix:~$ ls -l /dev/sda
brw-rw---- 1 root disk 8, 0 Aug 25 10:30 /dev/sda
O b no início (brw...) indica que é um dispositivo de bloco.
Dispositivo de Caractere (ex: um terminal virtual)
hacker@matrix:~$ ls -l /dev/tty1
crw--w---- 1 root tty 4, 1 Aug 25 10:31 /dev/tty1
O c no início (crw...) indica que é um dispositivo de caractere.
Pipe Nomeado (FIFO - First-In, First-Out)
hacker@matrix:~$ mkfifo ~/meu_pipe
hacker@matrix:~$ ls -l ~/meu_pipe
prw-r--r-- 1 hacker hacker 0 Aug 25 11:00 /home/hacker/meu_pipe
O 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.

📌 O que é `mkfifo`?
O comando `mkfifo` cria um FIFO especial (um named pipe, ou seja, “tubo nomeado”) no sistema de arquivos.
  • FIFO significa First In, First Out (“primeiro a entrar, primeiro a sair”).
  • É um mecanismo de comunicação entre processos (IPC – Inter-Process Communication).
  • Diferente de um arquivo normal, ele não armazena dados permanentemente: funciona como um túnel por onde um processo escreve e outro lê.
🔧 Exemplo básico
Crie um FIFO:
hacker@matrix:~$ mkfifo meu_pipe
Agora, no terminal, você verá um “arquivo especial”:
hacker@matrix:~$ ls -l meu_pipe
prw-r--r-- 1 hacker hacker 0 Aug 25 11:05 meu_pipe
📌 O “p” no início (prw-...) mostra que é um pipe nomeado.
🎭 Como usar
Abra dois terminais (ou use & para rodar em paralelo):
Terminal 1 (leitor):
hacker@matrix:~$ cat < meu_pipe
Esse comando vai ficar esperando dados no pipe.
Terminal 2 (escritor):
hacker@matrix:~$ echo "Olá, mundo!" > meu_pipe
➡ O texto "Olá, mundo!" aparece no Terminal 1. Repare que não foi gravado em disco: apenas transmitido de um processo para outro.
📖 Diferença para um pipe normal (`|`)
Pipe anônimo (`|`):
  • Existe apenas durante a execução do comando (ex: echo "teste" | grep t).
  • Não tem nome, não aparece no sistema de arquivos.
Pipe Nomeado (`mkfifo`):
  • Tem um nome no sistema de arquivos (ex: meu_pipe).
  • Pode ser aberto e usado por programas diferentes, mesmo que não sejam lançados juntos.
  • Serve como um ponto de encontro para processos se comunicarem.
💡 Usos práticos
  1. Comunicação entre processos longos: Um programa escreve logs no FIFO, outro os lê e processa em tempo real.
  2. Produtor/consumidor: Um script gera dados, outro consome, sem precisar de arquivos intermediários.
  3. Debugging ou simulação: Você pode usar `mkfifo` para testar como um programa reage a fluxos de dados contínuos.
⚠️ Observação
  • Se você escrever no FIFO e ninguém estiver lendo, o processo que escreve fica bloqueado até que alguém leia.
  • Se você tentar ler e ninguém escrever, o processo que lê também fica bloqueado até chegar algo.
🎯 Resumindo
  • mkfifo nome → cria um pipe nomeado (FIFO).
  • Funciona como um canal de comunicação entre processos, em que os dados passam “ao vivo” e não ficam gravados em disco.
  • É como se fosse um tubo invisível: o que entra de um lado, sai do outro, na mesma ordem.
EXERCÍCIO 13
A Função do Sistema de Arquivos `sysfs`
Objetivo: Descrever a função do `sysfs` e encontrar exemplos práticos em `/sys`.

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.

Ferramentas como udev e systemd usam o /sys extensivamente para detectar e configurar hardware automaticamente quando um dispositivo é conectado ou o sistema é inicializado.
Exemplo 1: Explorando a Estrutura

Podemos listar os diretórios principais para entender a organização do sysfs.

# Listar todas as classes de dispositivos (rede, som, energia, etc.)
hacker@matrix:~$ ls /sys/class
# Listar todos os dispositivos de bloco (discos, SSDs)
hacker@matrix:~$ ls /sys/block
# Listar todas as interfaces de rede
hacker@matrix:~$ ls /sys/class/net
Exemplo 2: Lendo Atributos de Hardware

Cada dispositivo expõe seus atributos como arquivos de texto simples.

# Verificar o status da bateria (em um notebook)
hacker@matrix:~$ cat /sys/class/power_supply/BAT0/capacity
95
# Verificar o estado de uma interface de rede (substitua 'eth0' pela sua)
hacker@matrix:~$ cat /sys/class/net/eth0/operstate
up
# Verificar se um disco é rotacional (HDD=1) ou não (SSD=0)
hacker@matrix:~$ cat /sys/block/sda/queue/rotational
0
Exemplo 3: Modificando o Comportamento do Kernel

Alguns arquivos no /sys permitem escrita, possibilitando a alteração de parâmetros do driver em tempo real.

# Ler o brilho máximo e o atual da tela
hacker@matrix:~$ cat /sys/class/backlight/intel_backlight/max_brightness
937
hacker@matrix:~$ cat /sys/class/backlight/intel_backlight/actual_brightness
500
# Alterar o brilho (requer privilégios de root)
hacker@matrix:~$ echo 700 | sudo tee /sys/class/backlight/intel_backlight/brightness
Escrever em arquivos no /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.
EXERCÍCIO 14
Medindo Tempo de Criação de Arquivos
Objetivo: Criar arquivos com dados nulos e aleatórios, medindo o tempo de execução.

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).

Usaremos o comando dd para ler de uma fonte e escrever em um destino, e o comando time como prefixo para medir o desempenho.
Criação do Arquivo Nulo (nulo.txt)
hacker@matrix:~$ time dd if=/dev/zero of=nulo.txt bs=1M count=10
10+0 records in 10+0 records out 10485760 bytes (10 MB, 10 MiB) copied, 0.005123 s, 2.0 GB/s real 0m0.006s user 0m0.000s sys 0m0.006s
Criação do Arquivo Aleatório (random_high_quality.txt)
hacker@matrix:~$ time dd if=/dev/random of=random_high_quality.txt bs=1M count=10
dd: error reading '/dev/random': Input/output error 0+0 records in 0+0 records out 0 bytes copied, 125.132 s, 0.0 kB/s real 2m5.133s user 0m0.000s sys 0m0.002s
A criação do arquivo com /dev/random pode ser extremamente lenta ou até mesmo falhar. Isso é esperado e será explicado na próxima questão.
EXERCÍCIO 15
Análise de Desempenho da Geração de Arquivos
Objetivo: Justificar a diferença de velocidade na criação dos arquivos do exercício anterior.

Considere o exercício 14 e responda. Qual geração de arquivo foi mais rápida? Por que? Justifique sua resposta.

A criação do arquivo nulo.txt a partir de /dev/zero foi incomparavelmente mais rápida. A razão está na natureza e complexidade das fontes de dados.
/dev/zero (Rápido)
Operação: Fornece um fluxo interminável de bytes nulos (\0).
Custo Computacional: Quase nulo. É uma tarefa de "copiar e colar" um valor constante.
Gargalo: A velocidade de escrita do seu disco.
/dev/random (Lento)
Operação: Gera números aleatórios criptograficamente seguros coletando "entropia" (aleatoriedade) de eventos de hardware (movimentos do mouse, interrupções de rede, etc.).
Custo Computacional: Intensivo.
Gargalo: O "pool de entropia". Se o pool se esgota, o /dev/random bloqueia (pausa) até coletar mais entropia, tornando o processo muito lento, especialmente em sistemas com pouca atividade.
Para a maioria dos casos (exceto criptografia de altíssima segurança), o dispositivo /dev/urandom é preferível. Ele é um meio-termo: suficientemente seguro e não bloqueia quando o pool de entropia se esgota.
EXERCÍCIO 16
Gerenciamento de Imagem de Disco e Partições
Objetivo: Criar, particionar, formatar, montar e usar uma imagem de disco virtual.

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.

Esta tarefa envolve vários passos e requer privilégios de administrador (sudo).
# 1. Criar a Imagem de Disco de 1GB
hacker@matrix:~$ dd if=/dev/zero of=disco.img bs=1G count=1
# 2. Particionar a Imagem
hacker@matrix:~$ sudo parted disco.img --script -- mklabel msdos mkpart primary ext4 1MiB 501MiB mkpart primary fat32 501MiB 1001MiB
# 3. Mapear Partições para Loop Devices
hacker@matrix:~$ LOOP_DEVICE=$(sudo losetup -fP --show disco.img)
# 4. Formatar as Partições
hacker@matrix:~$ sudo mkfs.ext4 ${LOOP_DEVICE}p1
hacker@matrix:~$ sudo mkfs.vfat ${LOOP_DEVICE}p2
# 5. Montar as Partições
hacker@matrix:~$ sudo mkdir -p /mnt/p1 /mnt/p2
hacker@matrix:~$ sudo mount ${LOOP_DEVICE}p1 /mnt/p1
hacker@matrix:~$ sudo mount ${LOOP_DEVICE}p2 /mnt/p2
# 6. Criar Arquivos nas Partições
hacker@matrix:~$ sudo dd if=/dev/zero of=/mnt/p1/f50 bs=1M count=50 status=none
hacker@matrix:~$ sudo dd if=/dev/zero of=/mnt/p2/f50 bs=1M count=50 status=none
# 7. Verificar o Espaço Usado
hacker@matrix:~$ df -hT /mnt/p1 /mnt/p2
Filesystem Type Size Used Avail Use% Mounted on /dev/loop0p1 ext4 488M 62M 392M 14% /mnt/p1 /dev/loop0p2 vfat 476M 50M 426M 11% /mnt/p2
# 8. Desmontar e Limpar
hacker@matrix:~$ sudo umount /mnt/p1 /mnt/p2
hacker@matrix:~$ sudo losetup -d ${LOOP_DEVICE}
hacker@matrix:~$ sudo rm -r /mnt/p1 /mnt/p2
Análise da Saída do `df -hT`: O espaço "Used" é maior que os 50MB do arquivo criado. A diferença corresponde ao espaço consumido pela própria estrutura do sistema de arquivos (metadados, journaling, etc.). O ext4, por ser mais robusto, geralmente consome mais espaço de metadados que o vfat.