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

He usado 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 lo hace? no ¿existe?

#!/bin/bash

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

preguntado el 12 de marzo de 09 a las 12:03

Siendo la persona muy perezosa que soy, normalmente habría usado la siguiente construcción tonta de solución alternativa: if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi; Probablemente sea bueno que encontré esta pregunta y aprendí a hacerla de una manera más adecuada. :) -

Para ser pendiente, debe decir "archivo normal", ya que la mayoría de los documentos UNIX / POSIX se refieren genéricamente a todos los tipos de entradas del sistema de archivos, simplemente "archivos", por ejemplo, un enlace simbólico es un tipo de archivo, al igual que una tubería con nombre. , archivo regular, directorio, bloque especial, carácter especial, socket, etc. -

@kevinarpe si quieres probar si algo existe, usa -e. -f no recogerá directorios, enlaces simbólicos, etc. -

Para estar seguro, use siempre comillas dobles para manejar correctamente los nombres de archivo con espacios en blanco, por ejemplo, FILE=$1 -> FILE="$1" y if [ -f $FILE ]; -> if [ -f "$FILE" ]; -

20 Respuestas

El test comando[ 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

Respondido el 13 de junio de 14 a las 15:06

Más sucintamente: [! -f /tmp/foo.txt] && echo "¡Archivo no encontrado!" - David Winterbottom

Luché un poco para encontrar la sintaxis correcta para "si alguno de los 2 archivos no existe". Lo siguiente ambos funcionan: if [ ! \( -f "f1" -a -f "f2" \) ] ; then echo MISSING; fi if [ ! -f "f1" ] || [ ! -f "f2" ] ; then echo MISSING; fi - mivk

@DavidWinterbottom Aún más suculento: [ -f /tmp/foo.txt ] || echo "File not found!" - David W.

El parámetro puede ser cualquiera de los siguientes: -e: Returns true value, if file exists -f: Return true value, if file exists and regular file -r: Return true value, if file exists and is readable -w: Return true value, if file exists and is writable -x: Return true value, if file exists and is executable -d: Return true value, if exists and is a directory - DAKOTA DEL SUR.

Existe una asimetría en el uso ! -f con && versus usar -f con ||. Esto tiene que ver con el código de salida devuelto por la verificación de inexistencia. Si necesita que su línea salga siempre limpiamente con el código de salida 0 (y, a veces, no desea esta restricción), los dos enfoques no son intercambiables. Alternativamente, use un if declaración y ya no tendrá que preocuparse por el código de salida de su verificación de inexistencia. - agudeza

Prueba de archivos Bash

-b filename - Bloquear archivo especial
-c filename - Archivo de caracteres especiales
-d directoryname - Compruebe la existencia del directorio
-e filename - Verifique la existencia del archivo, independientemente del tipo (nodo, directorio, socket, etc.)
-f filename - Verifique la existencia regular de archivos, no un directorio
-G filename - Verifique si el archivo existe y es propiedad de un ID de grupo efectivo
-G filename set-group-id - Verdadero si el archivo existe y es set-group-id
-k filename - Pegajoso
-L filename - Enlace simbólico
-O filename - Verdadero si el archivo existe y es propiedad del ID de usuario efectivo
-r filename - Compruebe si el archivo es legible
-S filename - Compruebe si el archivo es socket
-s filename - Compruebe si el tamaño del archivo es distinto de cero
-u filename - Compruebe si el archivo set-user-id bit está establecido
-w filename - Compruebe si el archivo se puede escribir
-x filename - Compruebe si el archivo es ejecutable

Modo de empleo:

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

A expresión de prueba se puede negar utilizando el ! operador

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

Respondido 08 Jul 16, 17:07

@ 0x90 Si lo desea, puede editar mi publicación y agregarla a la lista. Supongo que te refieres a: -n String - Compruebe si la longitud de la cadena no es cero. O te refieres file1 -nt file2 - Verifique si el archivo 1 es más nuevo que el archivo 2 (también puede usar -ot para más antiguo) - cactus azul

Acerca de -n: The unary operator -z tests for a null string, while -n or no operator at all returns True if a string is not empty. ~ ibm.com/developerworks/library/l-bash-test/index.html - cactus azul

por qué algunos no agregaron una función como función existe () {⏎ if [-e "$ 1"]; entonces echo "$ 1 existe" si no echo "$ 1 no existe" fi} - MzA

@MzA porque necesitamos hacer que el código sea legible, nadie sabe cuánto es $ 1. Así que asigne $ 1 como file y luego usa eso file variable para hacer otra cosa parece más legible que usar un argumento desconocido $1 - MaXi32

Puede negar una expresión con "!":

#!/bin/bash
FILE=$1

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

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

Respondido 07 Jul 17, 11:07

In golpear, [ es un incorporado. Entonces, la información relevante se obtiene más bien por help [... pero esto demuestra que [ es sinónimo de test incorporado, por lo tanto, la información relevante se obtiene más bien por help test. Ver también el Sección Bash Conditional Expression del manual. - gniourf_gniourf

@gniourf_gniourf: Sí, pero el bash integrado [ El comando se comporta de manera muy similar al externo [ comando, así que tampoco man test or man [ le dará una buena idea de cómo funciona. - Keith Thompson

@KeithThompson excepto que el golpear incorporado [ tiene más interruptores que el comando externo [ encontrado en mi sistema ... En general, creo que es mejor leer la documentación específica de una herramienta determinada, y no la documentación específica de otra vagamente relacionada. Aunque podría estar equivocado ;) - gniourf_gniourf

[[ -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 conector, un dispositivo o un dispositivo. Por ejemplo, para agregar una verificación de 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

Respondido el 14 de Septiembre de 14 a las 02:09

¿Puedo preguntar por qué las dos "[" en la prueba? (por ejemplo, [[! -a $ FILE]]). Probé todas las opciones mencionadas en una caja solaris y solo esa funcionó, muy agradecida, pero ¿por qué? - dimitrios mistriotis

Los corchetes dobles son una extensión "moderna"; por ejemplo, no dividirán palabras (como para nombres de archivos con espacios) y aún funcionan para cadenas vacías: mywiki.wooledge.org/BashFAQ/031 - bw1024

según tldp.org/LDP/abs/html/fto.html -a es idéntico en efecto a -e. Se ha "desaprobado" y se desaconseja su uso. De todos modos +1 por mencionar para verificar también el enlace simbólico roto - Luca Borrione

@dimitrismistriotis two "[" es una extensión no portátil implementada (de manera diferente) por zsh & bash; en general, debe evitarlo si es posible. - Buena persona

Ver SO 321348 por una buena razón -a no se puede negar en expresiones condicionales de un solo corchete. Evitar -a en conjunto, sugiero. - Steve Powell

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"

or

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

Respondido el 14 de Septiembre de 14 a las 02:09

¡Gracias! Necesitaba una alternativa que no utilice [[]] - Jonathan

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

$ [ -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 nunca uso la sintaxis completamente escrita!

Respondido 15 Abr '15, 08:04

En primer lugar, las referencias de variables sin comillas son propensas a errores. Dicho esto, ¿dónde dice en cualquier bash manpage que el [ or test incorporado probaría para existencia de archivos del argumento por defecto (a diferencia de -e)? ¿No sería ambiguo? AFAIK (y AIUI la sección "EXPRESIONES CONDICIONALES") lo único que se prueba con su enfoque es que el argumento no está vacío (o indefinido), que es, en este caso, una tautología (deje $DIR = '' y $FILE = '', entonces el argumento sigue siendo '//'). - Orejas puntiagudas

Prueba: ls /foo, resultado ls: cannot access /foo: No such file or directory. [ /foo ] && echo 42, resultado 42. GNU bash, versión 4.2.37 (1) -release (i486-pc-linux-gnu). - Orejas puntiagudas

@PointedEars: No pude especificar el -f opción, en el momento que escribí esta respuesta. Obviamente siempre podrías usar -e, si no está seguro de que será un archivo normal. Además, en todos mis guiones cito estos constructos, debí haberlos enviado sin las pruebas adecuadas. - JM Becker

ACK. Pero probablemente sepa que una sola línea no puede resolver el problema if-else: [ $condition ] && if_true || if_false es propenso a errores. En cualquier caso, encuentro [ ! -f "$file" ] && if_not_exists más fácil de leer y comprender que [ -f "$file" ] || if_not_exists. - Orejas puntiagudas

Para probar la existencia de un archivo, el parámetro puede ser uno 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, directorios y enlaces simbólicos normales:

-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

Script de ejemplo:

#!/bin/bash
FILE=$1

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

Respondido el 11 de enero de 17 a las 04:01

Puedes hacerlo:

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

or

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

Si desea verificar el archivo y la carpeta, use -e opción en lugar de -f. -e devuelve verdadero para archivos regulares, directorios, socket, archivos especiales de caracteres, archivos especiales de bloque, etc.

contestado el 09 de mayo de 18 a las 19:05

Eso no es específico de bash. La sintaxis proviene del shell Korn y también está disponible en zsh y bash. Tiene una ventaja limitada sobre el estándar. [ utilidad aquí sin embargo. - Stephane Chazelas

regular archivos (comprobados por -f) y directorios son solo dos de los muchos tipos diferentes de archivos. También hay enchufes, enlaces simbólicos, dispositivos, quince, puertas ... [ -e probará la existencia de archivos (de cualquier tipo, incluidos regulares, fijos, directorios ...) después de la resolución del enlace simbólico. - Stephane Chazelas

@StephaneChazelas: No veo ninguna etiqueta ksh o zsh en ninguna parte. Estamos hablando de bash o algo que está estandarizado en la mayoría de los sistemas Unix. Entonces, dentro del contexto, es específico de bash. OP no necesita conocer todos los proyectiles que existen: D - Yahid

Ese fue un comentario sobre el "Bash específico" parte de tu respuesta. - Stephane Chazelas

@StephaneChazelas: Sí, y dentro del contexto (bash y el sh estándar), es específico de bash. No veo el punto en tu segundo comentario, está totalmente fuera de contexto. OP no necesita -e, El necesita -f. - Yahid

Deberías tener cuidado al correr 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

Respondido 15 Abr '15, 08:04

La recomendación es tener cada variable entre comillas dobles, a menos que sepa exactamente que tiene uno de los raros casos en los que es innecesario o uno de los casos aún más raros en los que es dañino. (Y no, este no es uno de ellos). Uwe

¿Le importaría explicar por qué este no es el caso de usar comillas dobles? De lo contrario, no veo la utilidad en el comentario. - artdanil

Quiero decir: este no es uno de los raros casos en los que es innecesario o dañino. Un programador de shell debería acostumbrarse a encerrar (casi) todas las variables entre comillas dobles; esta regla no se limita a [ ... ]. - Uwe

In

[ -f "$file" ]

el [ comando hace un stat() (¿No estás registrado como lstat()) llamada al sistema en la ruta almacenada en $file y devoluciones verdadero si esa llamada al sistema tiene éxito y el tipo de archivo devuelto por stat() es "regular".

Entonces 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 vuelve false (o si [ ! -f "$file" ] or ! [ -f "$file" ] return true), hay muchas posibilidades diferentes:

  • el archivo no existe
  • el archivo existe pero no es un regular archivo (podría ser un dispositivo, quince, directorio, conector ...)
  • el archivo existe pero no tiene permiso de búsqueda en el directorio principal
  • el archivo existe pero esa ruta para acceder 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 que el stat() la llamada al sistema 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 el stat() llamada al sistema para volver con un código de error de ENOENT (ENOTDIR nos dice que uno de los componentes de la ruta no es un directorio es otro caso en el que podemos decir que el archivo no existe por esa ruta). Desafortunadamente, el [ 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.

El [ -e "$file" ] La prueba también se puede hacer con ls -Ld -- "$file" > /dev/null. En ese caso, ls te dirá por qué el stat() falló, 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 saber si el archivo existe o no. La [ comando simplemente ignoró el problema.

Con la zsh shell, puede consultar el código de error con el $ERRNO variable especial después de la falla [ comando, y decodificar ese número usando el $errnos matriz especial en el zsh/system módulo:

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;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi

(cuidado con el $errnos el soporte se rompió con algunas versiones de zsh cuando se construye con versiones recientes de gcc).

respondido 22 mar '19, 12:03

Hay tres formas distintas de hacer esto:

  1. Niegue 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 se han presentado la mayoría de las respuestas):

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

    o:

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

    Solamente:

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

    Esto parece una tontería (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 canalización (!):

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

Respondido 14 Oct 16, 22:10

Cualquier diferencia de portabilidad entre ! [ y [ !? - Llama congelada

El ! [ es POSIX para tuberías de shell 2.9.2 (cualquier comando) Otherwise, the exit status shall be the logical NOT of the exit status of the last command y [ ! es POSIX para prueba ! expression True if expression is false. False if expression is true. Por lo tanto, ambos son POSIX y, en mi experiencia, ambos son ampliamente compatibles. - usuario2350426

@FrozenFlame, el shell Bourne no tenía el ! palabra clave que fue introducida por el shell Korn. Sin embargo, a excepción de Solaris 10 y anteriores, es poco probable que se encuentre con un shell de Bourne en estos días. - Stephane Chazelas

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, presionando 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!"

contestado el 04 de mayo de 13 a las 23:05

El test la cosa también puede contar. Funcionó para mí (basado en Bash Shell: comprobar que el archivo existe o no):

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

Respondido el 26 de junio de 13 a las 18:06

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

Respondido 03 Jul 15, 09:07

La forma mas sencilla

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

Respondido 01 ago 15, 02:08

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

Respondido 05 ago 15, 22:08

No está claro que esto agregue algo que otras respuestas aún no hayan dado. Codifica de forma rígida un nombre de ruta. Dado que la pregunta está etiquetada golpear, podría usar read -p "Enter file name: " -r a tanto para indicar como para leer. Utiliza comillas alrededor de la variable; eso es bueno, pero debería explicarse. Sería mejor si hiciera eco del nombre del archivo. Y esto verifica que el archivo exista y no esté vacío (ese es el significado de -s) mientras que la pregunta se refiere a cualquier archivo, vacío o no (para el cual -f es más apropiado). - jonathan leffler

a veces puede resultar útil utilizar && y || operadores.

Como en (si tiene el comando "prueba"):

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

or

test -b $FILE || echo File there!

Respondido 11 Abr '17, 21:04

Si quieres usar test en lugar de [], entonces puedes usar ! para obtener la negación:

if ! test "$FILE"; then
  echo "does not exist"
fi

Respondido 28 ago 19, 10:08

También puede agrupar varios comandos en una sola línea.

[ -f "filename" ] || ( echo test1 && echo test2 && echo test3 )

or

[ -f "filename" ] || { echo test1 && echo test2 && echo test3 ;}

Si el nombre del archivo no sale, la salida será

test1
test2
test3

Nota: (...) se ejecuta en un subshell, {...;} se ejecuta en el mismo shell. La notación de corchetes solo funciona en bash.

Respondido el 07 de diciembre de 19 a las 03:12

No, la notación de corchetes es no solo bash; funciona en cualquier shell compatible con POSIX. - Carlos Duffy

La parte más interesante de tu respuesta es explicar la diferencia entre (...) y {...}! ¡No tenía ni idea de eso! Estoy aprendiendo todos los días ... ¡gracias! 🙏 - Gwyneth Llewelyn

envfile=.env

if [ ! -f "$envfile" ]
then
    echo "$envfile does not exist"
    exit 1
fi

Respondido el 04 de junio de 20 a las 03:06

Si bien este código puede resolver el problema del OP, es mejor incluir una explicación de cómo su código aborda el problema del OP. De esta manera, los futuros visitantes pueden aprender de su publicación y aplicarla a su propio código. SO no es un servicio de codificación, sino un recurso de conocimiento. Además, es más probable que se voten a favor las respuestas completas y de alta calidad. Estas características, junto con el requisito de que todas las publicaciones sean independientes, son algunas de las fortalezas de SO como plataforma, que la diferencia de los foros. Puede editar para agregar información adicional y / o complementar sus explicaciones con documentación fuente. - ysf

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.