Ao tentar obter um arquivo, você não desejaria um erro dizendo que o arquivo não existe para que você saiba o que corrigir?
Por exemplo, nvm recomenda adicionar isso ao seu perfil/rc:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Com acima, se nvm.sh
não existir, você receberá um "erro silencioso". Mas se você tentar . "$NVM_DIR/nvm.sh"
, a saída será FILE_PATH: No such file or directory
.
Em shells POSIX,
.
é um builtin especial, então sua falha faz com que o shell saia (em alguns shells comobash
, isso só é feito no modo POSIX).O que se qualifica como erro depende do shell. Nem todos eles saem após um erro de sintaxe ao analisar o arquivo, mas a maioria sairia quando o arquivo de origem não pudesse ser encontrado ou aberto. Não conheço nenhum que sairia se o último comando no arquivo de origem retornasse com um status de saída diferente de zero (a menos que a
errexit
opção esteja ativada, é claro).Aqui fazendo:
É um caso em que você deseja originar o arquivo se estiver lá e não se não estiver (ou estiver vazio aqui com
-s
).Ou seja, não deve ser considerado um erro (erro fatal em shells POSIX) se o arquivo não estiver lá, esse arquivo é considerado um arquivo opcional.
Ainda seria um erro (fatal) se o arquivo não fosse legível ou fosse um diretório ou (em alguns shells) se houvesse um erro de sintaxe ao analisá-lo, o que seria condições de erro reais que deveriam ser relatadas.
Alguns argumentariam que há uma condição de corrida. Mas a única coisa que isso significa seria que o shell sairia com um erro se o arquivo fosse removido entre
[
e.
, mas eu diria que é válido considerar um erro que esse arquivo de caminho fixo desapareceria repentinamente enquanto o script é corrida.Por outro lado,
onde
command
¹ remove o atributo especial.
do comando (para não sair do shell em caso de erro) não funcionaria como:.
os erros mas também os erros dos comandos executados no arquivo de origemOutras sintaxes comuns (veja por exemplo
grep -r /etc/default /etc/init*
em sistemas Debian para os scripts de inicialização que ainda não foram convertidossystemd
(ondeEnvironmentFile=-/etc/default/service
é usado para especificar um arquivo de ambiente opcional)) incluem:[ -e "$file" ] && . "$file"
Verifique se o arquivo está lá, ainda a fonte se estiver vazio. Ainda erro fatal se não puder ser aberto (mesmo que esteja lá ou estivesse lá). Você pode ver mais variantes como
[ -f "$file" ]
(existe e é um arquivo normal ),[ -r "$file" ]
(é legível) ou combinações delas.[ ! -e "$file" ] || . "$file"
Uma versão um pouco melhor. Deixa mais claro que o arquivo não existente é um caso OK. Isso também significa
$?
que refletirá o status de saída do último comando executado$file
(no caso anterior, se você obtiver1
, não saberá se é porque$file
não existia ou se esse comando falhou).command . "$file"
Espere que o arquivo esteja lá, mas não saia se não puder ser interpretado.
[ ! -e "$file" ] || command . "$file"
Combinação do acima: tudo bem se o arquivo não estiver lá e, para shells POSIX, falhas ao abrir (ou analisar) o arquivo são relatadas, mas não são fatais (o que pode ser mais desejável para
~/.profile
).¹ Nota: No
zsh
entanto, você não pode usarcommand
assim a não ser emsh
emulação; observe que no shell Korn,source
é na verdade um alias paracommand .
, uma variante não especial de.
Mantenedor da
nvm
resposta de :Minha interpretação (combinada com a excelente explicação de Stéphane e o comentário de Kusalananda):
É mais simples e seguro.
Ele defende contra shells POSIX saindo na inicialização devido a um arquivo ausente (por vários motivos). Aqueles que usam shells não POSIX (por exemplo, bash) podem remover a condicional se preferirem.
Como JBallin e Stéphane Chazelas apontaram, em shells POSIX, a fonte de um arquivo que não existe causaria falha no login.
Mas adicionar um teste para ver se o arquivo existe e tentar obtê-lo pode causar algo chamado condição de corrida. Se algo mudar
nvm.sh
entre o[ -s nvm.sh ]
e o. nvm.sh
, isso causará exatamente o bug que eles estão tentando evitar, embora muito mais raramente.Em geral, a maneira de evitar condições de corrida é apenas tentar o que você deseja fazer e, em seguida, lidar com o erro se ele falhar, por exemplo
Acontece que isso não funciona em shells POSIX, porque, como acima,
.
a falha fará com que o shell seja encerrado imediatamente, antes que qualquer tratamento de erro possa ser executado.Minha resposta argumenta que os shells POSIX não são relevantes para essa pergunta, porque
.bash_profile
nunca devem ser executados no modo POSIX. Então, podemos apenas fazer o código acima de qualquer maneira.Para ser mais seguro, podemos garantir que o modo POSIX não esteja em vigor ou garantir que o modo POSIX esteja desativado usando a técnica descrita em https://unix.stackexchange.com/a/383581/3169 .
A resposta de Stéphane tem algumas sugestões úteis sobre como lidar com todos os shells POSIX, que acho que foi a intenção do autor do nvm, mas foi sutilmente diferente do que a pergunta aqui estava perguntando, e é por isso que temos várias abordagens possíveis, dependendo de qual é seu objetivo .