Qual é a maneira mais adequada de distribuir scripts de shell, se os comportamentos dos shells puderem ser modificados set
e, portanto, imprevisíveis?
Por exemplo, rm *.txt
não seria executado conforme o esperado nos ambientes em que set -f
foi executado. Como devo garantir que rm *.txt
todos os arquivos de texto sejam removidos em um diretório atual em qualquer ambiente?
Como garantir que os scripts do shell sejam executados conforme o esperado antes de distribuí-los em geral?
bash
shell
shell-script
hoge
fonte
fonte
shell_state=$(set +o)
... script ...eval "$shell_state"
#!
para especificar quais opções de shell você deseja.Respostas:
Os scripts de shell normalmente são tratados como se fossem iguais a qualquer outro tipo de arquivo executável, como binários, scripts Python, scripts Perl ou qualquer outro tipo de script. Eles têm um shebang no topo que direciona o kernel para executá-los através do shell. Espera-se que eles sejam invocados da mesma maneira que qualquer outro comando.
Como tal, um novo shell é iniciado toda vez que o script é chamado, e quaisquer configurações como
set -f
presentes no shell de chamada ou em qualquer outra instância do shell no sistema são irrelevantes.Obviamente, é possível para os usuários obterem seu script em vez de executá-lo, por exemplo:
ou para executá-lo em um shell que tenha configurações não padrão como esta:
mas essas não são consideradas formas normais ou invocando seu script, e os usuários que fazem isso devem esperar o que receberem como resultado.
Observe que existem alguns scripts que devem ser originados, não executados, porque seu objetivo é alterar coisas do cwd ou definir variáveis de ambiente que devem ser refletidas no ambiente do shell de origem, mas estas são minoria e geralmente é feito como parte de um protocolo acordado. Esses arquivos podem ser considerados mais como "plugins" para qualquer sistema que eles esperem que sejam originados, não tanto quanto scripts independentes. Por exemplo, arquivos
/etc/rc*.d
com nomes que terminam em.sh
são originados pelo subsistema de script de inicialização, não são executados e está documentado que é isso que acontecerá se você colocar um arquivo com esse nome em/etc/rc*.d
e quando é feito, é feito de propósito. A convenção de nomear arquivos destinados a serem originados em vez de executados dessa maneira também é seguida em outros lugares, mas não universalmente.É verdade que os arquivos destinados a serem obtidos dessa maneira precisam cuidar de quais configurações podem estar presentes no ambiente do chamador que podem afetar o comportamento do shell, mas o protocolo acordado deve idealmente prometer um ambiente de execução previsível.
fonte
zsh
possui um recurso que permite restaurar as opções para um conjunto de informações em um contexto local (emulate -L zsh
) que é amplamente utilizado em todas as extensões enviadas com zsh e gravadas como código zsh. Veja como o sistema de conclusão do bash falha miseravelmente se você definir algumas opções comofailglob
.#! /bin/csh -f
vez de,#! /bin/csh
por exemplo.zshenv
. Cuidado com o que você colocazshenv
por esse motivo!emulate -L
neste caso) comentando uma das minhas respostas, e eu aprecio isso.~/.zshenv
(onde você deseja forçar as configurações (geralmente env vars) para todos os zshs (interativos ou não) chamados sob seu nome e geralmente não usados, exceto para solucionar algum outro problema não-zsh) é separado do~/.zshrc
(o arquivo interativo shell de personalização), portanto, é um recurso, não um bug. (você pode usar zsh -f) Um erro ocorre quando alguns shells bash não interativos lêem o seu~/.bashrc
(como over ssh e você precisa adicionar código para se proteger contra isso), ou alguns bash interativos (os de login) não o lêem. (e, novamente, você deve adicionar código ao seu~/.bash_profile
para solucionar esse problema).