Estoy tratando de escribir una if
declaración para probar si hay algún archivo que coincida con cierto patrón. Si hay un archivo de texto en un directorio, debe ejecutar un script determinado.
Mi código actualmente:
if [ -f /*.txt ]; then ./script fi
Por favor da algunas ideas; Solo quiero ejecutar el script si hay un .txt
en el directorio.
shell-script
files
wildcards
test
usuario40952
fuente
fuente
/
? Además, te falta un punto y coma antesfi
.find
como se explica aquí en stackoverflow .Respuestas:
devolvería verdadero solo si hay un (y solo uno) archivo no oculto en
/
cuyo nombre termina en.txt
y si ese archivo es un archivo normal o un enlace simbólico a un archivo normal.Esto se debe a que el shell expande los comodines antes de pasarlos al comando (aquí
[
).Así que si hay una
/a.txt
, y/b.txt
,[
será pasado 5 argumentos:[
,-f
,/a.txt
,/b.txt
y]
.[
luego se quejaría de que-f
se le dan demasiados argumentos.Si desea comprobar que el
*.txt
patrón se expande al menos a un archivo no oculto (normal o no):shopt -s nullglob
esbash
específico, pero como conchasksh93
,zsh
,yash
,tcsh
tienen declaraciones equivalentes.Tenga en cuenta que encuentra esos archivos leyendo el contenido del directorio, no intenta acceder a esos archivos en absoluto, lo que lo hace más eficiente que las soluciones que llaman comandos como
ls
ostat
en esa lista de archivos calculados por el shell.El
sh
equivalente estándar sería:El problema es que con los shells Bourne o POSIX, si un patrón no coincide, se expande a sí mismo. Entonces, si se
*.txt
expande a*.txt
, no sabes si es porque no hay un.txt
archivo en el directorio o porque hay un archivo llamado*.txt
. El uso[*].txt *.txt
permite discriminar entre los dos.fuente
[ -f /*.txt ]
es bastante rápido en comparación concompgen
.[ -f /*.txt ]
estaría equivocado, pero en mi prueba en un directorio que contiene3425
archivos,94
de los cuales son archivos txt no ocultos,compgen -G "*.txt" > /dev/null 2>&1
parecen ser tan rápidos comoset -- *.txt; [ "$#" -gt 0 ]
(20.5 segundos para ambos cuando se repiten 10000 veces en mi caso).Siempre puedes usar
find
:Explicación:
find .
: busca en el directorio actual-maxdepth 1
: no buscar subdirectorios-type f
: busca solo archivos regularesname "*.txt"
: busca archivos que terminan en.txt
2>/dev/null
: redirige los mensajes de error a/dev/null
| grep -q .
: grep para cualquier carácter, devolverá falso si no se encuentran caracteres.&& ./script
: Ejecutar./script
solo si el comando anterior fue exitoso (&&
)fuente
find
solo devuelve falso si tiene problemas para buscar archivos, no si no encuentra ningún archivo. Desea canalizar la salidagrep -q .
para verificar si encuentra algo.chmod a-x .
.Una posible solución es también Bash incorporado
compgen
. Ese comando devuelve todas las coincidencias posibles para un patrón global y tiene un código de salida que indica si algún archivo coincide.Encontré esta pregunta mientras buscaba soluciones más rápidas.
fuente
LC_ALL=C compgen -G "*.txt" > /dev/null
.Aquí hay un trazador de líneas para hacerlo:
existen archivos
los archivos no existen
Este enfoque hace uso de
||
y&&
operadores en bash. Estos son los operadores "o" y "y".Entonces, si el comando stat devuelve un
$?
igual a 0, entoncesecho
se llama al primero , si devuelve un 1, entonces el segundoecho
se llama .devolver resultados de stat
Esta pregunta está ampliamente cubierta en stackoverflow:
fuente
stat
cuandols -d
puede hacer lo mismo?ls -d
enumera un directorio? No pareció funcionar cuando intenté enumerar un directorio con archivos,ls -d *.pl
por ejemplo.&&
byls *.txt
y funcionará también. Asegúrese de enviar el stdout y stderr a/dev/null
lo sugerido por @slm.ls *.txt
y no hay archivos presentes en el directorio de este devolverá una$? = 2
, que seguirá funcionando con el caso entonces, pero esta fue una de mis razones para elegirstat
másls
. Quería un 0 para el éxito y un 1 para el fracaso.ls -d
es enumerar directorios en lugar de su contenido. Así quels -d
solo hace lolstat
en el archivo, tal como lostat
hace GNU . Lo que los comandos de estado de salida distintos de cero devuelven en caso de falla es específico del sistema, tiene poco sentido hacer suposiciones sobre ellos.Como señala Chazelas, su script fallaría si la expansión de comodines coincide con más de un archivo.
Sin embargo, hay un truco que uso ( aunque no me gusta mucho ) para evitarlo:
¿Cómo funciona?
La expansión de comodines coincidirá con una serie de nombres de archivos, obtenemos el primero si hay alguno, de lo contrario, nulo si no coincide.
fuente
.txt
archivos que son de tipo regular . Prueba por ejemplo despuésmkdir a.txt; mkfifo b.txt; echo regular > c.txt
.Simple como:
wc -l
cuenta las líneas en el comodín expandido.fuente
ls
salida y casi nunca examinarla$?
directamente porqueif
ya lo hace. Además, usarwc
para ver si sucedió algo está igualmente mal dirigido.Me gusta la solución de matriz anterior, pero eso podría ser un desperdicio con una gran cantidad de archivos: el shell usaría una gran cantidad de memoria para construir la matriz, y solo se probaría el primer elemento.
Aquí hay una estructura alternativa que probé ayer:
$ cd /etc; if [[ $(echo * | grep passwd) ]];then echo yes;else echo no;fi yes $ cd /etc; if [[ $(echo * | grep password) ]];then echo yes;else echo no;fi no
El valor de salida del grep parece estar determinando la ruta a través de la estructura de control. Esto también se prueba con expresiones regulares en lugar de patrones de shell. Algunos de mis sistemas tienen el comando "pcregrep" que permite coincidencias de expresiones regulares mucho más sofisticadas.
(Edité esta respuesta para eliminar un "ls" en la sustitución del comando después de leer la crítica anterior por analizarlo).
fuente
si desea usar una cláusula if, evalúe el recuento:
fuente