Resposta antiga de fórum: 3 comandos que não rodam mais
Comandos de fórum que quebraram no Debian 13, pip e PHP 8, com o substituto oficial testado e um script que data cada resposta do Stack Overflow antes de colar.
Três comandos que aparecem no topo da busca quando alguém configura um servidor Debian hoje: apt-key add para cadastrar um repositório, sudo pip install para instalar uma biblioteca Python e mysql_connect num tutorial de PHP. Os três foram rodados neste mês num Debian 13 limpo e num PHP 8.4. Nenhum funcionou. O que falha não é o fórum, é a data: cada resposta estava certa para a versão de quando foi escrita.
Este post mostra os três casos com a saída real do terminal, o substituto atual de cada um conferido na documentação oficial e um script curto que puxa, pela API pública do Stack Exchange, a data de criação e da última edição de cada resposta, além de apontar comandos que pedem leitura cuidadosa.
Caso 1: a chave do repositório com apt-key
A instrução clássica para adicionar o repositório do Docker (ou de quase qualquer fornecedor) era baixar a chave e jogar no chaveiro global do APT. Num contêiner debian:13 com APT 3.0.3, em outubro de 2026:
$ curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - bash: line 4: apt-key: command not found
O comando não está mais lá. E o problema dele nunca foi só estético: uma chave no chaveiro global vale para todos os repositórios configurados, então a chave de um fornecedor podia validar pacotes que chegassem por outro. O formato atual amarra cada chave a um repositório com Signed-By, e a documentação oficial do Docker para Debian já usa o arquivo .sources no formato deb822:
sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc . /etc/os-release sudo tee /etc/apt/sources.list.d/docker.sources <<EOF Types: deb URIs: https://download.docker.com/linux/debian Suites: $VERSION_CODENAME Components: stable Architectures: $(dpkg --print-architecture) Signed-By: /etc/apt/keyrings/docker.asc EOF sudo apt-get update
No teste, o apt-get update baixou o índice do Docker e o apt-cache policy docker-ce mostrou o candidato 5:29.9.2-1~debian.13~trixie. Para provar que a amarração funciona, o Signed-By foi apontado para outra chave (a do próprio Debian). O APT recusou o repositório:
Err:4 https://download.docker.com/linux/debian trixie InRelease Sub-process /usr/bin/sqv returned an error code (1), error message is: Missing key 7EA0A9C3F273FCD8, which is needed to verify signature.
É esse o comportamento que você quer: chave errada, repositório fora. A página do Debian sobre repositórios de terceiros descreve o mesmo modelo, e a man page sources.list(5) do trixie documenta os campos do deb822. Se o servidor também vai rodar contêineres, o post Docker no servidor: o primeiro container não é a arquitetura inteira continua daqui.
Caso 2: sudo pip install no Python do sistema
Respostas de 2015 a 2020 mandam instalar biblioteca com sudo pip install. No Debian 13, com pip 25.1.1 e Python 3.13:
$ pip install requests
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
O bloqueio vem da PEP 668: o Python do sistema pertence ao gerenciador de pacotes da distribuição, e um pip solto por cima pode quebrar ferramentas do próprio sistema que dependem de versões específicas. A especificação no guia de empacotamento do Python descreve o arquivo EXTERNALLY-MANAGED que liga essa trava. O caminho atual é um ambiente virtual por aplicação, com o módulo venv:
python3 -m venv /opt/app/.venv /opt/app/.venv/bin/pip install requests /opt/app/.venv/bin/python -c "import requests; print(requests.__version__)" # 2.34.2
Este caso mostra outra armadilha. A pergunta mais votada sobre esse erro no Stack Overflow tem respostas recentes, e quatro das mais votadas citam --break-system-packages. A opção existe, mas o nome já avisa o efeito: ela desliga a proteção que a PEP 668 criou. Resposta nova não é sinônimo de resposta segura. É preciso ler se ela recomenda a opção ou só explica por que evitá-la.
Caso 3: mysql_connect no tutorial de PHP
Tutorial de login com mysql_connect e mysql_query ainda circula em blog espelhado. No PHP 8.4.27:
$ php -r 'mysql_connect("localhost", "u", "p");'
PHP Fatal error: Uncaught Error: Call to undefined function mysql_connect()
A extensão saiu no PHP 7.0, como registra o guia de migração do PHP 7.0, e a própria página da função no manual manda usar MySQLi ou PDO. O risco aqui é o conserto apressado: trocar mysql_query por mysqli_query e manter a consulta montada com o texto do formulário. O erro some e a injeção de SQL fica. A troca correta usa PDO com parâmetro:
$pdo = new PDO('mysql:host=localhost;dbname=loja;charset=utf8mb4', $usuario, $senha, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
$stmt = $pdo->prepare('SELECT id, senha_hash FROM usuarios WHERE email = ?');
$stmt->execute([$_POST['email'] ?? '']);
$linha = $stmt->fetch(PDO::FETCH_ASSOC);
O post sobre tutorial de login PHP antigo percorre o resto da migração, incluindo o hash da senha.
Datar a resposta antes de ler o código
Nos três casos a pista estava na data, e o Stack Exchange expõe isso numa API pública que não exige cadastro para uso leve (sem chave de aplicativo, a cota que o teste mostrou foi de 300 chamadas por dia, e o próprio script imprime quanto resta). O script abaixo recebe o link de uma pergunta do Stack Overflow, Ask Ubuntu, Server Fault ou Super User e lista as respostas por voto, com data de criação, data da última edição e um aviso quando o código cita algo que hoje pede cuidado:
#!/usr/bin/env python3
"""Data e sinais de alerta das respostas de uma pergunta do Stack Exchange."""
import gzip, html, json, re, sys, urllib.request
from datetime import datetime, timezone
ALERTAS = {
r"\bapt-key\b": "cita apt-key (removido no apt do Debian 13)",
r"\bcurl\s+(-\w*k\b|--insecure)": "curl sem verificar certificado",
r"sslVerify\s+false": "git sem verificar certificado",
r"verify\s*=\s*False": "Python sem verificar certificado",
r"chmod\s+(-R\s+)?777": "chmod 777",
r"--break-system-packages": "cita --break-system-packages",
r"\bmysql_(connect|query)\b": "funções mysql_* (removidas no PHP 7)",
r"setenforce\s+0": "SELinux desligado",
}
def dia(ts):
return datetime.fromtimestamp(ts, timezone.utc).strftime("%Y-%m-%d") if ts else "nunca"
def main(url):
m = re.search(r"https?://([^/]+)/questions/(\d+)", url)
if not m:
sys.exit("use o link da pergunta: https://site/questions/NUMERO/...")
host, qid = m.groups()
site = host.removesuffix(".com").removesuffix(".stackexchange")
api = (f"https://api.stackexchange.com/2.3/questions/{qid}/answers"
f"?site={site}&sort=votes&order=desc&pagesize=10&filter=withbody")
with urllib.request.urlopen(api, timeout=20) as r:
bruto = r.read()
if bruto[:2] == b"\x1f\x8b": # a API costuma responder em gzip
bruto = gzip.decompress(bruto)
dados = json.loads(bruto)
for a in dados["items"]:
codigo = " ".join(re.findall(r"<code>(.*?)</code>", a["body"], re.S))
codigo = html.unescape(codigo)
achados = [nome for rx, nome in ALERTAS.items() if re.search(rx, codigo)]
print(f"{a['answer_id']:>9} votos {a['score']:>4} "
f"{'aceita ' if a['is_accepted'] else ' '}"
f"criada {dia(a['creation_date'])} "
f"editada {dia(a.get('last_edit_date'))}")
for nome in achados:
print(f"{'':11}alerta: {nome}")
print(f"cota restante da API hoje: {dados['quota_remaining']}")
if __name__ == "__main__":
main(sys.argv[1])
Rodando contra a pergunta do Ask Ubuntu sobre o substituto do apt-key:
$ python3 datar.py https://askubuntu.com/questions/1286545/
1307181 votos 368 criada 2021-01-11 editada 2026-10-07
alerta: cita apt-key (removido no apt do Debian 13)
1300076 votos 17 aceita criada 2020-12-14 editada nunca
1303285 votos 13 criada 2020-12-28 editada 2023-02-19
alerta: cita apt-key (removido no apt do Debian 13)
1321263 votos 12 criada 2021-03-05 editada 2022-10-13
alerta: cita apt-key (removido no apt do Debian 13)
1412554 votos 8 criada 2022-06-06 editada 2024-06-26
1400468 votos 7 criada 2022-04-01 editada 2022-06-07
alerta: cita apt-key (removido no apt do Debian 13)
1306494 votos 0 criada 2021-01-09 editada 2021-01-09
alerta: cita apt-key (removido no apt do Debian 13)
1470372 votos 0 criada 2023-06-02 editada nunca
cota restante da API hoje: 293
A leitura que importa está nas colunas, não nos votos. A resposta aceita é de dezembro de 2020 e nunca foi editada. A mais votada é de janeiro de 2021, mas foi editada em outubro de 2026, ou seja, alguém continua mantendo o texto. O aviso cita apt-key aparece nela porque ela explica a troca, não porque recomenda o comando; o script aponta onde ler com atenção, não decide sozinho. Contra a pergunta do erro externally-managed-environment, as quatro primeiras respostas recebem o aviso de --break-system-packages:
75722775 votos 795 criada 2023-03-13 editada 2025-12-17
alerta: cita --break-system-packages
76641565 votos 342 criada 2023-07-08 editada 2026-07-27
alerta: cita --break-system-packages
78652149 votos 227 criada 2024-06-21 editada 2025-12-15
alerta: cita --break-system-packages
76540031 votos 181 criada 2023-06-23 editada 2025-12-14
alerta: cita --break-system-packages
76672519 votos 63 criada 2023-07-12 editada 2024-06-06
O que conferir na sua máquina antes de colar
Com a data em mãos, o passo seguinte é comparar com o que está instalado, não com o que você lembra que está instalado:
cat /etc/os-release | head -3 # distribuição e versão apt --version # apt 3.0.3 no Debian 13 python3 --version; pip --version php -v | head -1 node -v
Se a resposta é anterior a um salto de versão (Debian 12 para 13, PHP 5 para 7, Python sem venv para PEP 668), procure o nome exato do comando no manual da versão instalada e no guia de migração entre as duas. Quando o manual diz removido ou obsoleto, a resposta terminou ali, por mais votos que tenha.
Alguns comandos merecem parada obrigatória, independentemente da data: curl -k ou --insecure, git config http.sslVerify false e verify=False no Python aceitam qualquer servidor fingindo ser o verdadeiro; chmod 777 dá escrita a qualquer processo da máquina; setenforce 0 desliga o SELinux inteiro para resolver uma permissão. Do lado do Windows, o equivalente é desligar o Defender para o instalador passar, e o post Defender bloqueou o instalador? Libere o arquivo mostra a liberação pontual que resolve sem abrir a máquina.
Por fim, teste num contêiner descartável antes do servidor. Os três casos deste post foram reproduzidos assim, com docker run --rm debian:13, e o contêiner some ao sair. Ao aplicar no servidor de verdade, anote o link da resposta e a data no commit ou no ticket: quando alguém estranhar aquela linha daqui a dois anos, vai saber de onde ela veio e de quando ela era.
Referência: https://br.answers.yahoo.com/