file-io español - ¿Cómo puedo saber si un archivo normal no existe en Bash?




scripting tutorial (15)

He usado el siguiente script 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 comprobar si el archivo no existe?

#!/bin/bash

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

Answers

Vale la pena mencionar que si necesita ejecutar un solo comando puede abreviar

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

a

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

o

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

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

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

La recomendación suele ser tener la variable probada entre comillas dobles:

#!/bin/sh
FILE=$1

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

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

La forma mas sencilla

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

Prueba de archivo Bash

-b filename - Bloquear archivo especial
-c filename - archivo de caracteres especiales
-d directoryname - Comprobar existencia de directorio
-e filename : compruebe la existencia del archivo, independientemente del tipo (nodo, directorio, socket, etc.)
-f filename : compruebe si existe un archivo normal, no un directorio
-G filename : verifique si el archivo existe y es propiedad del ID de grupo efectivo
-G filename set-group-id - Verdadero si el archivo existe y es set-group-id
-k filename - bit pegajoso
-L filename - enlace simbólico
-O filename : verdadero si el archivo existe y es propiedad del ID de usuario efectivo
-r filename : verifica si el archivo es legible
-S filename - Comprobar si el archivo es socket
-s filename : compruebe si el archivo es de tamaño distinto de cero
-u filename : comprueba si el archivo set-user-id bit está establecido
-w filename - Verifica si el archivo es de escritura
-x filename - Comprueba 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 la tecla ! operador

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

El comando de test ( [ aquí) tiene un operador lógico "no" que es el signo de exclamación (similar a muchos otros idiomas). Prueba esto:

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

Prefiero hacer lo siguiente de una sola línea, 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, ya casi no uso la sintaxis completamente escrita!


Hay tres formas distintas de hacer esto:

  1. Negar el estado de salida con bash (ninguna otra respuesta ha dicho esto):

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

    O:

    ! [ -e "$file" ] && echo "file does not exist"
    
  2. Negar la prueba dentro del comando de prueba [ (esa es la forma en que la mayoría de las respuestas antes se presentaron):

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

    O:

    [ ! -e "$file" ] && echo "file does not exist"
    
  3. Actúe sobre el resultado de que la prueba sea negativa ( || lugar de && ):

    Solamente:

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

    Esto parece ridículo (IMO), no lo use a menos que su código tenga que ser portátil al shell Bourne (como el /bin/sh de Solaris 10 o anterior) que carecía del operador de negación de la tubería ( ! ):

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

Para probar la existencia del archivo, el parámetro puede ser cualquiera de los siguientes:

-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

Todas las pruebas a continuación se aplican a archivos regulares, directorios y enlaces simbólicos:

-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

Ejemplo de script:

#!/bin/bash
FILE=$1

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

En

[ -f "$file" ]

el comando [ hace una llamada al sistema stat() (no lstat() ) en la ruta almacenada en $file y devuelve true si la llamada al sistema es exitosa y el tipo del archivo tal como lo devuelve stat() es "regular".

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

Sin embargo, si devuelve falso (o si [ ! -f "$file" ] o ! [ -f "$file" ] devuelve verdadero), 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 para el directorio principal
  • el archivo existe pero la 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 involucrados en la resolución del enlace simbólico.
  • ... cualquier otra razón por la cual la llamada al 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 saber con certeza que el archivo no existe, necesitaríamos la llamada al sistema stat() para regresar con un código de error de ENOENT ( ENOTDIR nos dice que uno de los componentes de la ruta no es un directorio; otro caso donde podemos decirlo) el archivo no existe por esa ruta). Desafortunadamente 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, ls le dirá por qué falló el stat() , aunque la información no se puede usar fácilmente mediante programación:

$ 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 existe 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 [ 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, el soporte de $errnos se rompe con algunas versiones de zsh cuando se construye con versiones recientes de gcc ).


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

Puedes hacerlo:

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

o

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

Si desea verificar el archivo y la carpeta, use la opción -e lugar de -f . -e devuelve true para archivos normales, directorios, socket, archivos especiales de caracteres, archivos especiales de bloques, etc.


Puedes negar una expresión con "!":

#!/bin/bash
FILE=$1

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

La página man relevante es man test o, de manera equivalente, man [ - o help test o help [ para el comando bash incorporado.



Utilice la bandera -p.

man mkdir
mkdir -p foo






bash file-io scripting