tutorial script lenguaje example español bash file-io scripting

script - ¿Cómo puedo saber si un archivo normal no existe en Bash?



bash scripting tutorial español (17)

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


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


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


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


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


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



La forma mas sencilla

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


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


Para revertir una prueba, use "!". Eso es equivalente al operador "no" lógico 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, presing todos juntos:

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

Que se puede escribir (usando entonces "y" operador: &&) como:

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

Que se ve más corto así:

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


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!


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.


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"


a veces puede ser útil usar && y || operadores

Al igual que en (si tiene comando "prueba"):

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

o

test -b $FILE || echo File there!


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


[[ -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