Introdução
Um script de shell armazena comandos em um arquivo para que uma tarefa possa ser repetida de forma consistente. Scripts confiáveis para iniciantes deixam explícito o interpretador, usam aspas nas expansões de variáveis, validam a entrada antes de agir e retornam um status de saída que outros comandos conseguem interpretar.
Neste laboratório, você criará pequenos scripts Bash de forma incremental. Você executará scripts por meio do Bash e como arquivos executáveis, usará variáveis e argumentos posicionais, lerá entradas interativas, tomará decisões com if e testes de arquivos, escolherá códigos de saída, percorrerá arquivos com for e combinará esses conceitos em um simples resumidor de logs.
Crie e execute seu primeiro script
Nesta etapa, você criará um script Bash, executá-lo-á por meio de um interpretador e o tornará diretamente executável.
Acesse o diretório de trabalho do laboratório:
cd /home/labex/project/shell-lab
Crie hello.sh com um here-document. A primeira linha é um shebang que seleciona o Bash quando o arquivo é executado diretamente:
cat > hello.sh <<'EOF'
#!/bin/bash
echo "Hello from a Bash script"
pwd
EOF
Inspecione o arquivo antes de executá-lo:
cat hello.sh
Passe o arquivo explicitamente ao Bash. Isso funciona mesmo antes de adicionar a permissão de execução:
bash hello.sh
Adicione a permissão de execução e verifique o modo do arquivo:
chmod u+x hello.sh
ls -l hello.sh
Execute o arquivo a partir do diretório atual. ./ fornece um caminho; normalmente, o shell não pesquisa automaticamente no diretório atual:
./hello.sh
Use variáveis e aspas com segurança
Nesta etapa, você atribuirá valores a variáveis, expandirá essas variáveis e verá por que as aspas duplas protegem valores que contêm espaços.
Crie um script com duas variáveis:
cat > variables.sh <<'EOF'
#!/bin/bash
course="Linux for Noobs"
workspace="/home/labex/project/shell-lab"
echo "Course: $course"
echo "Workspace: $workspace"
printf 'Quoted argument count: %s\n' "$#"
printf 'First argument: %s\n' "${1:-not provided}"
EOF
Não coloque espaços ao redor de = em uma atribuição do shell. As aspas duplas permitem expandir $course e, ao mesmo tempo, manter Linux for Noobs como um único valor.
Execute o script com um argumento que contém espaços:
bash variables.sh "beginner learner"
A variável especial $# representa o número de argumentos posicionais, enquanto $1 representa o primeiro argumento. ${1:-not provided} fornece um valor alternativo quando o argumento está ausente.
Salve a saída para inspeção:
bash variables.sh "beginner learner" > variable-output.txt
cat variable-output.txt
Valide argumentos posicionais
Nesta etapa, você exigirá um argumento, exibirá instruções de uso e retornará status de saída diferentes para indicar falha e sucesso.
Crie greet-argument.sh:
cat > greet-argument.sh <<'EOF'
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Usage: $0 NAME" >&2
exit 2
fi
name=$1
echo "Hello, $name"
exit 0
EOF
O comando de teste [ ... ] verifica se a quantidade de argumentos é diferente de um. >&2 envia o texto de uso para a saída de erro padrão, e exit 2 informa que o uso foi inválido.
Execute o script sem argumento e, em seguida, exiba imediatamente $?, que contém o status de saída do comando anterior:
bash greet-argument.sh
echo "missing argument status: $?"
O status esperado é 2. Agora execute o script corretamente:
bash greet-argument.sh "Ada Lovelace"
echo "valid argument status: $?"
Salve a saudação bem-sucedida:
bash greet-argument.sh "Ada Lovelace" > argument-greeting.txt
Leia entradas interativas
Nesta etapa, você solicitará um valor ao usuário, lerá uma linha com segurança e tratará o caso de entrada vazia.
Crie ask-name.sh:
cat > ask-name.sh <<'EOF'
#!/bin/bash
read -r -p "Enter your name: " name
if [ -z "$name" ]; then
echo "A name is required" >&2
exit 1
fi
echo "Welcome, $name"
EOF
read -r lê uma linha sem tratar barras invertidas de forma especial. -p exibe um prompt, e -z verifica se o valor entre aspas está vazio.
Execute o script:
bash ask-name.sh
No prompt, digite:
Grace Hopper
Você deverá ver Welcome, Grace Hopper. Para gerar um resultado salvo e reproduzível, encaminhe uma linha de entrada para o mesmo script:
printf 'Grace Hopper\n' | bash ask-name.sh > interactive-greeting.txt
cat interactive-greeting.txt
Tome decisões usando testes de arquivos
Nesta etapa, você usará if, elif e else com testes de arquivos para classificar um caminho.
Crie classify-path.sh:
cat > classify-path.sh <<'EOF'
#!/bin/bash
path=${1:-}
if [ -z "$path" ]; then
echo "Usage: $0 PATH" >&2
exit 2
elif [ -d "$path" ]; then
echo "directory: $path"
elif [ -f "$path" ]; then
echo "file: $path"
else
echo "missing: $path" >&2
exit 1
fi
exit 0
EOF
-d verifica se o caminho corresponde a um diretório, e -f verifica se corresponde a um arquivo comum. A ordem é importante: o uso inválido é tratado antes da classificação do caminho.
Teste os três resultados possíveis:
bash classify-path.sh logs
bash classify-path.sh notes.txt
bash classify-path.sh missing.txt
echo "missing path status: $?"
Salve juntos os resultados bem-sucedidos. && executa o segundo comando somente se o primeiro for concluído com sucesso:
bash classify-path.sh logs > path-results.txt && bash classify-path.sh notes.txt >> path-results.txt
cat path-results.txt
Processe vários arquivos com um loop for
Nesta etapa, você percorrerá arquivos de log e contará os registros correspondentes em cada um deles.
Crie count-errors.sh:
cat > count-errors.sh <<'EOF'
#!/bin/bash
log_dir=${1:-logs}
if [ ! -d "$log_dir" ]; then
echo "Log directory not found: $log_dir" >&2
exit 1
fi
for log_file in "$log_dir"/*.log; do
error_count=$(grep -c '^ERROR ' "$log_file" || true)
printf '%s errors=%s\n' "$(basename "$log_file")" "$error_count"
done
EOF
A cada iteração, o loop atribui a log_file um dos caminhos correspondentes. Colocar "$log_file" entre aspas protege os espaços, enquanto basename remove o prefixo do diretório. grep -c conta as linhas correspondentes; || true impede que a ausência de correspondências interrompa um fluxo de trabalho maior configurado para falhar estritamente.
Execute o loop e salve sua saída:
bash count-errors.sh logs | tee error-counts.txt
Você deverá ver um resultado para cada arquivo .log.
Combine validação, loops e status de saída
Nesta etapa, você criará um script reutilizável que valida um diretório, resume seus logs e informa claramente se a execução foi bem-sucedida ou não.
Crie summarize-logs.sh:
cat > summarize-logs.sh <<'EOF'
#!/bin/bash
input_dir=${1:-}
output_file=${2:-}
if [ -z "$input_dir" ] || [ -z "$output_file" ]; then
echo "Usage: $0 INPUT_DIR OUTPUT_FILE" >&2
exit 2
fi
if [ ! -d "$input_dir" ]; then
echo "Input directory not found: $input_dir" >&2
exit 1
fi
: > "$output_file"
for log_file in "$input_dir"/*.log; do
lines=$(wc -l < "$log_file")
errors=$(grep -c '^ERROR ' "$log_file" || true)
printf '%s lines=%s errors=%s\n' "$(basename "$log_file")" "$lines" "$errors" >> "$output_file"
done
echo "Wrote summary to $output_file"
exit 0
EOF
O comando : > "$output_file" cria o arquivo de destino, caso ele não exista, ou limpa seu conteúdo antes do loop. Execute o script fornecendo os dois argumentos obrigatórios:
chmod u+x summarize-logs.sh
./summarize-logs.sh logs log-summary.txt
echo "summary status: $?"
cat log-summary.txt
Teste o caminho de falha usando um diretório inexistente:
./summarize-logs.sh missing log-summary.txt
echo "missing directory status: $?"
O status de sucesso deverá ser 0, enquanto o status para um diretório inexistente deverá ser 1.
Resumo
Você criou e executou scripts Bash, usou shebangs e permissões, expandiu variáveis entre aspas, leu entradas posicionais e interativas e retornou status de saída significativos. Também tomou decisões com if/elif/else, testou arquivos e diretórios, percorreu logs com for e combinou esses conceitos em um resumidor reutilizável.
Esses fundamentos tornam as automações futuras mais fáceis de ler, mais seguras para executar novamente e mais simples de avaliar por outros comandos ou tarefas agendadas.



