¿Cómo puedo saber si un archivo regular no existe en Bash?


Answers

Bash File Testing

-b filename - Bloquear archivo especial
-c filename - archivo de caracteres especiales
-d directoryname - Comprobar la existencia del directorio
-e filename : compruebe la existencia del archivo, independientemente del tipo (nodo, directorio, socket, etc.)
-f filename - Verificar existencia de archivo regular no un directorio
-G filename - Verifique si el archivo existe y es propiedad de una identificación de grupo efectiva
-G filename set-group-id - True si el archivo existe y es set-group-id
-k filename - Sticky bit
-L filename - Enlace simbólico
-O filename - Verdadero si el archivo existe y es propiedad de la identificación de usuario efectiva
-r filename - Comprobar si el archivo es legible
-S filename - Verificar si el archivo es socket
-s filename - Comprueba si el archivo tiene un tamaño distinto de cero
-u filename - Verifica si el archivo set-user-id bit está configurado
-w filename - Comprobar si el archivo es escribible
-x filename - Comprobar si el archivo es ejecutable

Cómo utilizar:

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

Una expresión de prueba puede ser negada usando el ! operador

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

He utilizado la siguiente secuencia de comandos para ver si existe un archivo:

#!/bin/bash

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

¿Cuál es la sintaxis correcta para usar si solo quiero verificar si el archivo no existe?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi



Debe tener cuidado al ejecutar la test para una variable sin comillas, ya que puede producir resultados inesperados:

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

La recomendación generalmente es tener la variable probada rodeada de comillas dobles:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi



En

[ -f "$file" ]

el [ comando realiza una llamada al sistema stat() (no lstat() ) en la ruta almacenada en $file y devuelve verdadero si la llamada al sistema tiene éxito y el tipo del archivo devuelto por stat() es "regular".

Entonces, si [ -f "$file" ] devuelve verdadero, puede decir que el archivo existe y que es un archivo regular o un enlace simbólico que finalmente se convierte en un archivo normal (o al menos en el momento de la stat() ).

Sin embargo, si devuelve falso (o si [ ! -f "$file" ] o ! [ -f "$file" ] return true), hay muchas posibilidades diferentes:

  • el archivo no existe
  • el archivo existe pero no es un archivo normal
  • el archivo existe pero no tiene permiso de búsqueda en el directorio padre
  • el archivo existe pero esa ruta de acceso es demasiado larga
  • el archivo es un enlace simbólico a un archivo normal, pero no tiene permiso de búsqueda para algunos de los directorios implicados en la resolución del enlace simbólico.
  • ... cualquier otra razón por la cual la llamada del sistema stat() puede fallar.

En resumen, debería 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 estar seguros de que el archivo no existe, necesitaríamos la llamada al sistema stat() para devolver con un código de error de ENOENT ( ENOTDIR nos dice que uno de los componentes de ruta no es un directorio es otro caso en el que podemos decir el archivo no existe por esa ruta). Lamentablemente, el [ comando no nos deja saber eso. Devolverá falso si el código de error es ENOENT, EACCESS (permiso denegado), ENAMETOOLONG o cualquier otra cosa.

La prueba [ -e "$file" ] también se puede hacer con ls -Ld -- "$file" > /dev/null . En ese caso, le dirá por qué falló la stat() , aunque la información no puede ser utilizada de forma programática fácilmente:

$ 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

Al menos, ls me dice que no es porque el archivo no exista, que falla. Es porque no puede decir si el archivo existe o no. El [ comando simplemente ignoró el problema.

Con el shell zsh , puede consultar el código de error con la variable especial $ERRNO después del comando de falla [ y decodificar ese número usando la matriz especial $errnos en el 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 con el soporte de $errnos roto con algunas versiones de zsh cuando se zsh con versiones recientes de gcc ).




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

Además, es posible que el archivo sea un enlace simbólico roto, o un archivo no regular, como por ejemplo un socket, dispositivo o fifo. Por ejemplo, para agregar un cheque para enlaces simbólicos rotos:

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



Este script de shell también funciona para encontrar un archivo en un directorio:

echo "enter file"

read -r a

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



Prefiero hacer el siguiente one-liner, en formato compatible con shell POSIX :

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

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

Para un par de comandos, como lo haría en un script:

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

¡Una vez que comencé a hacer esto, raramente uso la sintaxis completamente tipada más !!




Este código también funciona.

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



Para revertir una prueba, use "!". Eso es equivalente al operador lógico "no" en otros idiomas. Prueba esto:

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

O escrito de una manera ligeramente diferente:

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

O podrías usar:

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

O, prescribiendo todos juntos:

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

Que puede escribirse (usando el operador "y": &&) como:

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

Que se ve más corto así:

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



Links