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:
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"
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"
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 cosa de la test
puede contar también. Funcionó para mí (basado en Bash Shell: Verifique si el archivo existe o no ):
test -e FILENAME && echo "File exists" || echo "File doesn''t exist"
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