Como posso saber se um arquivo regular não existe no Bash?

Eu usei o seguinte script para ver se existe um arquivo:

#!/bin/bash FILE=$1 if [ -f $FILE ]; then echo "File $FILE exists." else echo "File $FILE does not exist." fi 

Qual é a syntax correta para usar se eu quiser apenas verificar se o arquivo não existe?

 #!/bin/bash FILE=$1 if [ $FILE does not exist ]; then echo "File $FILE does not exist." fi 

O comando de teste ( [ aqui] tem um operador lógico “não”, que é o ponto de exclamação (semelhante a muitos outros idiomas). Tente isto:

 if [ ! -f /tmp/foo.txt ]; then echo "File not found!" fi 

Teste de arquivo de bash

-b filename – Bloquear arquivo especial
-c filename – arquivo de caractere especial
-d directoryname – Verifique o diretório Existence
-e filename – Verifica a existência do arquivo, independentemente do tipo (nó, diretório, soquete, etc.)
-f filename – Verificar existência de arquivo regular e não um diretório
-G filename – Verifique se o arquivo existe e é de propriedade de um ID de grupo efetivo
-G filename set-group-id – Verdadeiro se o arquivo existir e for set-group-id
-k filename – Sticky bit
-L filename – Link simbólico
-O filename – Verdadeiro se o arquivo existir e pertencer ao ID do usuário efetivo
-r filename – Verifique se o arquivo é legível
-S filename – Verifique se o arquivo é o soquete
-s filename – Verifique se o arquivo tem tamanho diferente de zero
-u filename – Verifique se o bit set-user-id está definido
-w filename – Verifique se o arquivo é gravável
-x filename – Verifique se o arquivo é executável

Como usar:

 #!/bin/bash file=./file if [ -e "$file" ]; then echo "File exists" else echo "File does not exist" fi 

Uma expressão de teste pode ser negada usando o ! operador

 #!/bin/bash file=./file if [ ! -e "$file" ]; then echo "File does not exist" else echo "File exists" fi 

Você pode negar uma expressão com “!”:

 #!/bin/bash FILE=$1 if [ ! -f "$FILE" ] then echo "File $FILE does not exist" fi 

A man page relevante é man test ou, equivalentemente, man [ – ou help test ou help [ para o comando bash integrado.

 [[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE" 

Além disso, é possível que o arquivo seja um link simbólico quebrado ou um arquivo não regular, como, por exemplo, um soquete, dispositivo ou fifo. Por exemplo, para adicionar uma verificação de links simbólicos quebrados:

 if [[ ! -f $FILE ]]; then if [[ -L $FILE ]]; then printf '%s is a broken symlink!\n' "$FILE" else printf '%s does not exist!\n' "$FILE" fi fi 

Vale a pena mencionar que, se você precisar executar um único comando, poderá abreviá-lo

 if [ ! -f "$file" ]; then echo "$file" fi 

para

 test -f "$file" || echo "$file" 

ou

 [ -f "$file" ] || echo "$file" 

Eu prefiro fazer o seguinte one-liner, no formato compatível com shell POSIX :

 $ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND" $ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND" 

Por alguns comandos, como eu faria em um script:

 $ [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;} 

Depois que comecei a fazer isso, raramente uso mais a syntax totalmente digitada !!

Para testar a existência do arquivo, o parâmetro pode ser qualquer um dos seguintes:

 -e: Returns true if file exists (regular file, directory, or symlink) -f: Returns true if file exists and is a regular file -d: Returns true if file exists and is a directory -h: Returns true if file exists and is a symlink 

Todos os testes abaixo se aplicam a arquivos, diretórios e links simbólicos regulares:

 -r: Returns true if file exists and is readable -w: Returns true if file exists and is writable -x: Returns true if file exists and is executable -s: Returns true if file exists and has a size > 0 

Exemplo de script:

 #!/bin/bash FILE=$1 if [ -f "$FILE" ]; then echo "File $FILE exists" else echo "File $FILE does not exist" fi 

Você deve ter cuidado ao executar o test para uma variável sem aspas, porque pode produzir resultados inesperados:

 $ [ -f ] $ echo $? 0 $ [ -f "" ] $ echo $? 1 

A recomendação é geralmente ter a variável testada entre aspas duplas:

 #!/bin/sh FILE=$1 if [ ! -f "$FILE" ] then echo "File $FILE does not exist." fi 

Existem três maneiras distintas de fazer isso:

  1. Negue o status de saída com bash (nenhuma outra resposta disse isso):

     if ! [ -e "$file" ]; then echo "file does not exist" fi 

    Ou:

     ! [ -e "$file" ] && echo "file does not exist" 
  2. Negue o teste dentro do comando test [ (é assim que a maioria das respostas anteriores foi apresentada):

     if [ ! -e "$file" ]; then echo "file does not exist" fi 

    Ou:

     [ ! -e "$file" ] && echo "file does not exist" 
  3. Agir sobre o resultado do teste sendo negativo ( || invés de && ):

    Somente:

     [ -e "$file" ] || echo "file does not exist" 

    Isso parece bobo (IMO), não o use a menos que seu código precise ser portável para o shell Bourne (como o /bin/sh do Solaris 10 ou anterior) que não possuísse o operador de negação de pipeline ( ! ):

     if [ -e "$file" ]; then : else echo "file does not exist" fi 

Você consegue fazer isso:

 [[ ! -f "$FILE" ]] && echo "File doesn't exist" 

ou

 if [[ ! -f "$FILE" ]]; then echo "File doesn't exist" fi 

Se você quiser verificar o arquivo e a pasta, use a opção -e vez de -f . -e retorna true para arquivos regulares, diretórios, socket, arquivos especiais de caracteres, arquivos especiais de bloco, etc.

Dentro

 [ -f "$file" ] 

o [ comando faz uma chamada de sistema stat() (não lstat() ) no caminho armazenado em $file e retorna true se a chamada do sistema for bem-sucedida e o tipo do arquivo retornado por stat() for “regular”.

Então, se [ -f "$file" ] retornar true, você pode dizer que o arquivo existe e é um arquivo regular ou um symlink que eventualmente resolve um arquivo regular (ou pelo menos era no momento do stat() ).

No entanto, se ele retornar false (ou se [ ! -f "$file" ] ou ! [ -f "$file" ] retornar true), existem muitas possibilidades diferentes:

  • o arquivo não existe
  • o arquivo existe, mas não é um arquivo normal
  • o arquivo existe, mas você não tem permissão de pesquisa para o diretório pai
  • o arquivo existe, mas o caminho para acessá-lo é muito longo
  • o arquivo é um link simbólico para um arquivo normal, mas você não tem permissão de busca para alguns dos diretórios envolvidos na resolução do symlink.
  • … qualquer outro motivo pelo qual a chamada do sistema stat() pode falhar.

Em suma, deve ser:

 if [ -f "$file" ]; then printf '"%s" is a path to a regular file or symlink to regular file\n' "$file" elif [ -e "$file" ]; then printf '"%s" exists but is not a regular file\n' "$file" elif [ -L "$file" ]; then printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file" else printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file" fi 

Para ter certeza de que o arquivo não existe, precisamos da chamada do sistema stat() para retornar com um código de erro ENOENT ( ENOTDIR nos diz que um dos componentes do caminho não é um diretório é outro caso em que podemos dizer o arquivo não existe por esse caminho). Infelizmente o [ comando não nos deixa saber disso. Ele retornará false se o código de erro for ENOENT, EACCESS (permissão negada), ENAMETOOLONG ou qualquer outra coisa.

O teste [ -e "$file" ] também pode ser feito com ls -Ld -- "$file" > /dev/null . Nesse caso, ls dirá por que o stat() falhou, embora as informações não possam ser usadas facilmente programaticamente:

 $ file=/var/spool/cron/crontabs/root $ if [ ! -e "$file" ]; then echo does not exist; fi does not exist $ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi ls: cannot access '/var/spool/cron/crontabs/root': Permission denied stat failed 

Pelo menos, ls me diz que não é porque o arquivo não existe que ele falha. É porque não pode dizer se o arquivo existe ou não. O [ comando apenas ignorou o problema.

Com o shell zsh , você pode consultar o código de erro com a variável especial $ERRNO após o comando [ comando, e decodificar esse número usando o array especial $errnos no módulo zsh/system :

 zmodload zsh/system ERRNO=0 if [ ! -f "$file" ]; then err=$ERRNO case $errnos[err] in ("") echo exists, not a regular file;; (ENOENT|ENOTDIR) if [ -L "$file" ]; then echo broken link else echo does not exist fi;; (*) echo "can't tell"; syserror "$err" esac fi 

(cuidado, o suporte a $errnos foi quebrado com algumas versões do zsh quando $errnos com versões recentes do gcc ).

Para reverter um teste, use “!”. Isso é equivalente ao operador “não” lógico em outros idiomas. Tente isto:

 if [ ! -f /tmp/foo.txt ]; then echo "File not found!" fi 

Ou escrito de uma maneira um pouco diferente:

 if [ ! -f /tmp/foo.txt ] then echo "File not found!" fi 

Ou você poderia usar:

 if ! [ -f /tmp/foo.txt ] then echo "File not found!" fi 

Ou, presing todos juntos:

 if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi 

Que pode ser escrito (usando então “e” operador: &&) como:

 [ ! -f /tmp/foo.txt ] && echo "File not found!" 

Que parece mais curto assim:

 [ -f /tmp/foo.txt ] || echo "File not found!" 

O test também pode contar. Funcionou para mim (com base no Bash Shell: verificar arquivo existe ou não ):

 test -e FILENAME && echo "File exists" || echo "File doesn't exist" 

Este código também está funcionando.

 #!/bin/bash FILE=$1 if [ -f $FILE ]; then echo "File '$FILE' Exists" else echo "The File '$FILE' Does Not Exist" fi 

A maneira mais simples

 FILE=$1 [ ! -e "${FILE}" ] && echo "does not exist" || echo "exists" 

Este script de shell também funciona para localizar um arquivo em um diretório:

 echo "enter file" read -ra if [ -s /home/trainee02/"$a" ] then echo "yes. file is there." else echo "sorry. file is not there." fi 

às vezes pode ser útil usar o && and || operadores.

Como em (se você tiver o comando “teste”):

 test -b $FILE && echo File not there! 

ou

 test -b $FILE || echo File there!