`ps aux` escrito em Bash sem fork
(github.com/izabera)izabera/psé uma implementação em Bash para imitar, dentro do Bash, uma saída próxima deps auxmesmo em situações em que não é possível criar novos processos- A condição principal é um cenário em que há um bash shell confiável em uma máquina acessada via
ssh, mas todos os outros PIDs estão em uso e não é possível criar um novo processo - O README apresenta essa situação como um exemplo de pergunta de entrevista para uma vaga que exige conhecimentos de Bash/Linux
- A ferramenta é descrita como algo que permite “fingir mais ou menos” que se tem acesso a um
ps auxfuncional, sem garantir que seja uma implementação substituta completa - A frase “funciona 100% em todas as máquinas e em todas as situações” é claramente usada como uma garantia em tom de brincadeira
Que tipo de projeto é este
- É um projeto que implementa
ps auxapenas com Bash - O título do README é “
ps auxwritten entirely in bash without ever forking” - A principal característica do projeto é que ele não faz fork em nenhum momento durante a execução
Situação considerada
- O cenário de exemplo é o seguinte
- Você está conectado à máquina via
ssh - O usuário está em um bash shell familiar
- Mas todos os outros PIDs estão em uso, então não é possível criar nenhum novo processo
- Você está conectado à máquina via
- O README apresenta que, nessas condições, pode ser necessário algo parecido com
ps aux
Escopo esperado e ressalvas
- A ferramenta é apresentada como uma forma de “kinda sorta pretend” que existe um
ps auxfuncional - A frase do README dizendo que é “garantido funcionar perfeitamente em 100% das máquinas, em todas as situações” é usada como humor exagerado
- Portanto, o ponto central da descrição não é compatibilidade completa, mas sim imitar
ps auxapenas com Bash em um ambiente extremo no qual não é possível criar novos processos
1 comentários
Opiniões no Hacker News
A piada de que o problema mais difícil da ciência da computação acabou sendo alinhar colunas faz sentido
Já escrevi inúmeras funções de alinhamento de colunas em várias linguagens, e sempre foi sofrido; na cabeça parece simples, algo como “calcular o maior comprimento de cada coluna e inserir espaços até o próximo múltiplo do tamanho da tabulação”
Mesmo usando f-strings e recursos de padding do Python, o código rapidamente fica complexo e difícil de ler; é tão horrível que, enquanto reescrevia um exemplo para um comentário, corrigi vários bugs
Para um uso tão comum, parece óbvio que deveria haver uma biblioteca; sinceramente, é surpreendente que isso não exista na biblioteca padrão
A abordagem extrai as larguras e os nomes das colunas a partir do
descriptiondo cursor do banco de dados, monta a linha separadora e a string de formato e então imprime as linhas; não sei se há algum bug fatal que eu tenha deixado passar, e não parece um problema especialmente difícilzip(*table)para transpor as colunas, calcular o maior comprimento de cada uma e imprimir alinhado comf"{r:<{w}}"O resultado de exemplo vira uma tabela com larguras de coluna alinhadas, como
agony | kick | pumpOs valores contêm espaços, são preenchidos com espaços e, às vezes, o alinhamento sai errado ou os dados transbordam a coluna
Talvez fosse melhor todos combinarmos de não usar dados alinhados em colunas e adotar um formato mais simples e legível por humanos; todos sairiam ganhando
Se eu entrasse por SSH em uma máquina na qual o shell Bash ainda está vivo, mas todos os PIDs foram esgotados e não é possível criar novos processos, eu vasculharia o sistema de arquivos
/proc/[pid]/para descobrir qual processo está esgotando o espaço de PIDsO
killdo Bash é um comando embutido do shell, então não precisa fazer fork de um novo processo como/bin/killSe for possível encontrar o processo pai que está gerando os filhos que esgotam os PIDs, dá para interrompê-lo e recuperar o controle do sistema
Este script também faz parsing de
/proce não usa pipes nem substituições$(...)que criariam um novo subshell Bash, então é bem limpoAssim, seria possível chamar as funções POSIX necessárias sem executar um comando separado, o que gerou uma boa reação
Reiniciar e recuperar depois pode ser mais rápido do que encontrar e matar o processo pai em um ambiente restrito; se os PIDs acabaram, é provável que outras coisas também já estejam em mau estado
ps(){ (cd /proc;for i in [0-9]*;do echo $i: $(tr '\0' ' ' < $i/cmdline);done); }/proc/[pid]/para ver qual processo está esgotando o espaço de PIDs está correta, mas pelos comentários no código-fonte parece que inicialmente se esperava que apenas/proc/*/statusfosse suficiente; valores como uso de CPU, porém, não podiam ser obtidos dali[[ $cmdline ]] && exec {cmdline}>&-eexec {cmdline}< "$dir"/cmdline || continuefuncionamEm 2011, fiz entrevista para uma função de SRE em uma empresa de tecnologia bem grande dos EUA; na época, foi a primeira vez que ouvi o termo SRE
A empresa estava criando uma alternativa ao MS Office baseada em navegador e, depois da triagem por telefone, eu precisava programar em tempo real conversando com o entrevistador dentro do editor de documentos da própria empresa
Como eu tinha dado notas altas para
shell scriptingeLinuxna autoavaliação, recebi a tarefa de criar um substituto paranetstatem Bash, mas na época eu não sabia onde nem como as informações de sockets ficavam em/proc/, então rapidamente concluí que não conseguiriaEm vez disso, propus criar versões reduzidas de
psefuser, e a solução que apresentei naquele terrível processador de texto baseado em navegador foi aceita, me levando até a entrevista presencialPensando agora, talvez o cenário hipotético que motivava esse exercício estivesse mais enraizado na realidade do que eu imaginava
Eu também começaria por aí
Há algum tempo criei, por diversão, um site interativo para explorar a situação de estar conectado por SSH e não conseguir criar novos processos: https://oops.cmdchallenge.com
"echo *"não lista todos os arquivos do diretórioÉ preciso usar
"echo .* *"Eu queria olhar a lista de
"View Solutions"das outras etapas para ver que outras abordagens eram possíveisIzabera é um dos especialistas de #bash@libera
Desde os tempos do antigo freenode, aprendi muita coisa com esse tipo de especialista ao longo dos últimos 10 anos
Isto é um Bash bem limpo
Pela minha experiência, código Bash costuma ser mal escrito e ineficiente, mas este parece ser um bom exemplo do contrário
E se você estiver em um shell POSIX confiável que não tem suporte a Bash?
Este script Bash não é compatível com POSIX
Este script não funciona no Bash 3.2, mas funciona no Bash 4.2
No Bash 3.2, ocorre o erro
printf: '(': invalid format character; o ambiente de exemplo ébash-3.2-33.el5_11.4.0.1Um uso melhor talvez seja ver a lista de processos em um sistema onde procps não está instalado
Bacana
Também dá para criar listeners e clientes em Bash
Não recomendo para uso real