Distribution de scripts: empacotamento e instalação

1. Fundamentos da Distribuição de Scripts Bash

Distribuir um script Bash vai muito além de compartilhar um arquivo. Envolve considerar dependências (como jq, curl, bc), o runtime (geralmente /bin/bash ou /usr/bin/env bash) e a portabilidade entre distribuições Linux e até mesmo macOS.

1.1 Estrutura de diretórios recomendada

Um projeto bem organizado segue esta estrutura:

meu-script/
├── bin/
│   └── meu-script
├── man/
│   └── man1/
│       └── meu-script.1
├── lib/
│   └── funcoes.sh
├── tests/
│   └── test_meu-script.sh
├── Makefile
├── README.md
└── LICENSE

1.2 Padrões FHS e locais de instalação

O Filesystem Hierarchy Standard (FHS) define locais apropriados:

  • /usr/local/bin — para scripts instalados manualmente pelo administrador
  • /opt/<nome-do-pacote>/ — para pacotes autocontidos
  • ~/.local/bin — para instalação por usuário (sem privilégios root)

2. Empacotamento Manual com make install

2.1 Criando um Makefile

PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
MANDIR ?= $(PREFIX)/share/man/man1
DESTDIR ?=

.PHONY: install uninstall checksum

install:
    install -d $(DESTDIR)$(BINDIR)
    install -d $(DESTDIR)$(MANDIR)
    install -m 755 bin/meu-script $(DESTDIR)$(BINDIR)/
    install -m 644 man/man1/meu-script.1 $(DESTDIR)$(MANDIR)/

uninstall:
    rm -f $(DESTDIR)$(BINDIR)/meu-script
    rm -f $(DESTDIR)$(MANDIR)/meu-script.1

checksum:
    sha256sum bin/meu-script > checksums.sha256

2.2 Variáveis de instalação

# Instalação para diretório do usuário
make install PREFIX=~/.local

# Instalação em diretório temporário (para empacotamento)
make install DESTDIR=/tmp/meu-pacote

2.3 Geração de checksum

sha256sum bin/meu-script > meu-script.sha256
sha256sum -c meu-script.sha256

3. Empacotamento para Gerenciadores de Pacotes

3.1 Construção de pacotes .deb

Estrutura necessária:

meu-script_1.0/
├── DEBIAN/
│   ├── control
│   ├── preinst
│   └── postinst
└── usr/
    └── local/
        └── bin/
            └── meu-script

Arquivo DEBIAN/control:

Package: meu-script
Version: 1.0
Section: utils
Priority: optional
Architecture: all
Depends: bash (>= 4.0), jq, curl
Maintainer: Seu Nome <email@exemplo.com>
Description: Ferramenta de automação em Bash
 Script para gerenciamento de tarefas de DevOps.

Construção:

dpkg-deb --build meu-script_1.0

3.2 Construção de pacotes .rpm

Arquivo .spec:

Name: meu-script
Version: 1.0
Release: 1
Summary: Ferramenta de automação em Bash
License: MIT
Source: %{name}-%{version}.tar.gz
BuildArch: noarch
Requires: bash >= 4.0, jq, curl

%description
Script para gerenciamento de tarefas de DevOps.

%install
mkdir -p %{buildroot}/usr/local/bin
install -m 755 bin/meu-script %{buildroot}/usr/local/bin/

%files
/usr/local/bin/meu-script

Construção:

rpmbuild -ba meu-script.spec

3.3 Scripts de pré/pós-instalação

#!/bin/bash
# postinst - executado após instalação
if ! command -v jq &> /dev/null; then
    echo "AVISO: jq não está instalado. Instale com: apt install jq"
fi

4. Distribuição via Repositórios Git e Tarballs

4.1 Versionamento semântico e tags

git tag -a v1.0.0 -m "Versão 1.0.0 - Lançamento inicial"
git push origin v1.0.0

4.2 Geração de tarballs assinados

git archive --format=tar.gz --prefix=meu-script-1.0/ v1.0.0 > meu-script-1.0.tar.gz
gpg --sign --detach-sign meu-script-1.0.tar.gz
sha256sum meu-script-1.0.tar.gz > meu-script-1.0.tar.gz.sha256

4.3 Scripts de instalação "one-liner"

curl -fsSL https://exemplo.com/install.sh | bash

Riscos: esse método permite execução de código arbitrário sem verificação. Mitigação:

curl -fsSL https://exemplo.com/install.sh -o install.sh
sha256sum -c install.sh.sha256 && bash install.sh

5. Empacotamento com Ferramentas Especializadas

5.1 Uso de shar (shell archive)

shar bin/meu-script lib/funcoes.sh > meu-script.shar
chmod +x meu-script.shar
./meu-script.shar  # auto-extração

5.2 Empacotamento com makeself

makeself --gzip --sha256 ./meu-script-dir \
    meu-script-installer.run \
    "Instalador do Meu Script" \
    ./bin/meu-script --install

5.3 Alternativa: AppImage para scripts

Embora AppImage seja mais comum para aplicações gráficas, é possível empacotar scripts Bash usando appimagetool com um runtime mínimo.

6. Instalação e Atualização Automatizada

6.1 Script de auto-atualização

#!/bin/bash
VERSION="1.0.0"
REMOTE_URL="https://exemplo.com/meu-script-latest"
LOCAL_BIN="/usr/local/bin/meu-script"

check_update() {
    local remote_version=$(curl -fsSL "$REMOTE_URL/version.txt")
    if [ "$remote_version" != "$VERSION" ]; then
        echo "Nova versão disponível: $remote_version"
        curl -fsSL "$REMOTE_URL/meu-script" -o /tmp/meu-script-new
        sha256sum -c "$REMOTE_URL/meu-script.sha256" && \
            install -m 755 /tmp/meu-script-new "$LOCAL_BIN"
    fi
}

6.2 Gerenciamento de dependências

#!/bin/bash
check_deps() {
    local deps=("jq" "curl" "bc" "git")
    local missing=()

    for dep in "${deps[@]}"; do
        if ! command -v "$dep" &> /dev/null; then
            missing+=("$dep")
        fi
    done

    if [ ${#missing[@]} -gt 0 ]; then
        echo "Dependências ausentes: ${missing[*]}"
        echo "Instale com: sudo apt install ${missing[*]}"
        exit 1
    fi
}

6.3 Rollback e desinstalação

#!/bin/bash
uninstall() {
    local files=(
        "/usr/local/bin/meu-script"
        "/usr/local/share/man/man1/meu-script.1"
        "/etc/meu-script/config.cfg"
    )

    for file in "${files[@]}"; do
        if [ -f "$file" ]; then
            rm -i "$file"
        fi
    done

    # Limpeza de PATH e variáveis de ambiente
    sed -i '/meu-script/d' ~/.bashrc
    echo "Desinstalação concluída."
}

7. Boas Práticas de Segurança na Distribuição

7.1 Assinatura digital com GPG

# Gerar chave
gpg --full-generate-key

# Assinar script
gpg --detach-sign --armor meu-script

# Verificar assinatura
gpg --verify meu-script.asc meu-script

7.2 Validação de checksums

#!/bin/bash
validate_package() {
    local url="$1"
    local checksum_url="$2"
    local temp_file=$(mktemp)

    curl -fsSL "$url" -o "$temp_file"
    curl -fsSL "$checksum_url" -o "$temp_file.sha256"

    if sha256sum -c "$temp_file.sha256" --status; then
        echo "Checksum válido. Executando instalação..."
        bash "$temp_file"
    else
        echo "ERRO: Checksum inválido! Pacote corrompido ou adulterado."
        exit 1
    fi
}

7.3 Sanitização de entradas

#!/bin/bash
sanitize_input() {
    local input="$1"
    # Remove caracteres perigosos
    input="${input//[^a-zA-Z0-9_\/.-]/}"
    echo "$input"
}

# Uso seguro
read -r user_input
safe_input=$(sanitize_input "$user_input")

8. Casos de Uso e Exemplos Práticos

8.1 Distribuição via curl | bash com fallback seguro

#!/bin/bash
# Script de instalação seguro
set -euo pipefail

INSTALLER_URL="https://exemplo.com/meu-script/install.sh"
CHECKSUM_URL="https://exemplo.com/meu-script/install.sh.sha256"
GPG_SIG_URL="https://exemplo.com/meu-script/install.sh.asc"

# Download com verificação
curl -fsSL "$INSTALLER_URL" -o /tmp/install.sh
curl -fsSL "$CHECKSUM_URL" -o /tmp/install.sh.sha256
curl -fsSL "$GPG_SIG_URL" -o /tmp/install.sh.asc

# Verificação GPG
gpg --verify /tmp/install.sh.asc /tmp/install.sh || {
    echo "Falha na verificação GPG!"
    exit 1
}

# Verificação SHA256
sha256sum -c /tmp/install.sh.sha256 || {
    echo "Falha na verificação SHA256!"
    exit 1
}

# Execução segura
bash /tmp/install.sh

8.2 Pacote .deb para ferramenta DevOps

#!/bin/bash
# Construção automatizada de pacote .deb
VERSION="1.0.0"
PACKAGE_NAME="meu-script_${VERSION}_all.deb"

# Preparar estrutura
mkdir -p build/DEBIAN
mkdir -p build/usr/local/bin

# Copiar script
cp bin/meu-script build/usr/local/bin/
chmod 755 build/usr/local/bin/meu-script

# Criar arquivo control
cat > build/DEBIAN/control << EOF
Package: meu-script
Version: $VERSION
Section: utils
Priority: optional
Architecture: all
Depends: bash (>= 4.0), jq, curl
Maintainer: DevOps Team <devops@exemplo.com>
Description: Ferramenta interna de automação
 Script para deploy e monitoramento de serviços.
EOF

# Construir pacote
dpkg-deb --build build "$PACKAGE_NAME"
echo "Pacote gerado: $PACKAGE_NAME"

8.3 Integração com CI/CD

#!/bin/bash
# .github/workflows/release.yml (GitHub Actions)
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Build package
        run: |
          make build
          make deb
          make rpm

      - name: Generate checksums
        run: |
          sha256sum *.deb *.rpm > checksums.txt

      - name: Sign artifacts
        run: |
          gpg --detach-sign --armor *.deb
          gpg --detach-sign --armor *.rpm

      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          files: |
            *.deb
            *.rpm
            checksums.txt
            *.asc

Referências