AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 450239
Accepted
JBallin
JBallin
Asked: 2018-06-17 17:17:52 +0800 CST2018-06-17 17:17:52 +0800 CST 2018-06-17 17:17:52 +0800 CST

Quando (ou por que) você deve verificar a existência de um arquivo antes de buscá-lo?

  • 772

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.shnã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.

shell-script
  • 3 3 respostas
  • 2433 Views

3 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2018-06-17T22:15:24+08:002018-06-17T22:15:24+08:00

    Em shells POSIX, .é um builtin especial, então sua falha faz com que o shell saia (em alguns shells como bash, 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 errexitopção esteja ativada, é claro).

    Aqui fazendo:

    [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
    

    É 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,

    command . "$NVM_DIR/nvm.sh" 2> /dev/null
    

    onde command¹ remove o atributo especial. do comando (para não sair do shell em caso de erro) não funcionaria como:

    • ocultaria .os erros mas também os erros dos comandos executados no arquivo de origem
    • também ocultaria condições de erro reais, como o arquivo com as permissões erradas.

    Outras 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 convertidos systemd(onde EnvironmentFile=-/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ê obtiver 1, não saberá se é porque $filenã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 zshentanto, você não pode usar commandassim a não ser em shemulação; observe que no shell Korn, sourceé na verdade um alias para command ., uma variante não especial de.

    • 25
  2. JBallin
    2018-06-17T23:32:49+08:002018-06-17T23:32:49+08:00

    Mantenedor da nvmresposta de :

    é fácil desinstalar o nvm simplesmente excluindo o arquivo; forçar trabalho adicional (para rastrear onde estão as linhas desse nvm de origem) não parece particularmente valioso.

    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.

    • 5
  3. Mikel
    2018-06-21T09:13:18+08:002018-06-21T09:13:18+08:00

    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.shentre 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

    . "$NVM_DIR/nvm.sh" || echo "Sourcing $NVM_DIR/nvm.sh failed" >&2
    

    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_profilenunca 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 .

    • 1

relate perguntas

  • Subtraindo a mesma coluna entre duas linhas no awk

  • Um script que imprime as linhas de um arquivo com seu comprimento [fechado]

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • MySQL Select com função IN () com array bash

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve