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 especificam explicitamente o interpretador, colocam as expansões de variáveis entre aspas, 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 progressivamente. Você executará scripts pelo Bash e como arquivos executáveis, usará variáveis e argumentos posicionais, lerá entradas interativas, criará ramificações com if e testes de arquivos, escolherá códigos de saída, iterará com for e combinará essas ideias em um simples resumidor de logs.
Crie e execute seu primeiro script
Nesta etapa, você criará um script Bash, executará esse script por meio de um interpretador e o tornará diretamente executável.
Entre no 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 para o Bash. Isso funciona mesmo antes de adicionar a permissão de execução:
bash hello.sh
Adicione a permissão de execução e inspecione 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 de forma segura
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 manter Linux for Noobs como um único valor.
Execute o script com um argumento que contenha espaços:
bash variables.sh "beginner learner"
A variável especial $# contém o número de argumentos posicionais, e $1 contém o primeiro argumento. ${1:-not provided} fornece um valor alternativo quando o primeiro argumento não foi informado.
Salve a saída para inspecioná-la:
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 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 não é igual a um. >&2 envia o texto de uso para o erro padrão, e exit 2 informa que o uso é inválido.
Execute o script sem um argumento e, logo em seguida, exiba $?, que contém o status de saída do comando anterior:
bash greet-argument.sh
echo "missing argument status: $?"
O status esperado é 2. 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 uma entrada interativa
Nesta etapa, você solicitará um valor ao usuário, lerá uma linha com segurança e tratará uma 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 as 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 salvar um resultado reproduzível, envie uma linha de entrada pelo pipe para o mesmo script:
printf 'Grace Hopper\n' | bash ask-name.sh > interactive-greeting.txt
cat interactive-greeting.txt
Crie ramificações com 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 é um diretório, e -f verifica se é um arquivo regular. A ordem é importante: o uso inválido é tratado antes do tipo do caminho.
Teste os três resultados possíveis para o caminho:
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 bem-sucedido:
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ê iterará sobre 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
O loop atribui um caminho correspondente a log_file em cada iteração. 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 e estrito.
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 operação foi bem-sucedida ou falhou.
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 destino ou esvazia seu conteúdo com segurança antes do loop. Execute o script com 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 deve ser 0, enquanto o status do diretório inexistente deve 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. Você também criou ramificações com if/elif/else, testou arquivos e diretórios, iterou sobre logs com for e combinou essas ideias em um resumidor reutilizável.
Esses fundamentos tornam a automação posterior mais fácil de ler, mais segura para executar novamente e mais simples de ser avaliada por outros comandos ou tarefas agendadas.



