12 votos

Cómo pasar '*' comodín para el parámetro de la ruta de comando buscar a través de una variable en un script?

Quiero usar find para encontrar archivos en un conjunto de carpetas restringidas por los comodines, pero donde no hay espacios en el nombre de ruta de acceso.

Desde la línea de comandos, esto es fácil. Todos los ejemplos siguientes de trabajo.

find  te*/my\ files/more   -print
find  te*/'my files'/more  -print
find  te*/my' 'files/more  -print

Estos se encuentran los archivos, por ejemplo, terminal/my files/more y tepid/my files/more.

Sin embargo, yo necesito esto para ser parte de una secuencia de comandos; lo que necesito es algo como esto:

SEARCH='te*/my\ files/more'
find ${SEARCH} -print

Por desgracia, todo lo que hago, no parece ser capaz de mezclar los comodines y los espacios en un find comando dentro de una secuencia de comandos. El ejemplo anterior devuelve el siguiente error (nota de la inesperada duplicación de la barra diagonal inversa):

find: ‘te*/my\\': No such file or directory
find: ‘files/more': No such file or directory

Tratando de utilizar comillas también falla.

SEARCH="te*/'my files'/more"
find ${SEARCH} -print

Esto devuelve los siguientes errores, haber ignorado el significado de las citas:

find: ‘te*/'my': No such file or directory
find: ‘files'/more': No such file or directory

He aquí un ejemplo más.

SEARCH='te*/my files/more'
find ${SEARCH} -print

Como se esperaba:

find: ‘te*/my': No such file or directory
find: ‘files/more': No such file or directory

Cada una de las variantes que he intentado devuelve un error.

Tengo una solución, la cual es potencialmente peligroso porque vuelve demasiadas carpetas. Puedo convertir todos los espacios a un signo de interrogación (de un solo carácter comodín) como este:

SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?}       # Convert every space to a question mark.
find ${SEARCH} -print

Esto es el equivalente a:

find te*/my?files/more -print

Esto devuelve no sólo la correcta carpetas, pero también terse/myxfiles/more, que no se supone que.

¿Cómo puedo lograr lo que yo estoy tratando de hacer? Google no ha ayudado a mí :(

10voto

Stewart Puntos 1385

El mismo comando debería funcionar bien en una secuencia de comandos:

#!/usr/bin/env bash
find  te*/my\ files/ -print

Si usted necesita para tenerlo como una variable, se hace un poco más complejo:

#!/usr/bin/env bash
search='te*/my\ files/'
eval find "$search" -print

ADVERTENCIA:

El uso de eval como que no es seguro y puede resultar en la ejecución arbitraria y, posiblemente, de código dañino si los nombres de archivo pueden contener ciertos personajes. Ver bash FAQ 48 para más detalles.

Es mejor pasar la ruta de acceso como argumento:

#!/usr/bin/env bash
find "$@" -name "file*"

Otro enfoque es evitar find en total, y el uso de bash extendido englobamiento de las características y globs:

#!/usr/bin/env bash
shopt -s globstar
for file in te*/my\ files/**; do echo "$file"; done

El globstar bash opción le permite usar ** a coincidir de forma recursiva:

globstar
      If set, the pattern ** used in a pathname expansion con‐
      text will match all files and zero or  more  directories
      and  subdirectories.  If the pattern is followed by a /,
      only directories and subdirectories match.

Para hacer que la ley 100% como encontrar e incluir dotfiles (archivos ocultos), el uso de

#!/usr/bin/env bash
shopt -s globstar
for file in te*/my\ files/**; do echo "$file"; done
shopt -s dotglob 

Usted puede incluso echo directamente sin el bucle:

echo te*/my\ files/**

2voto

muru Puntos 43315

Cómo acerca de las matrices?

$ tree Desktop/ Documents/
Desktop/
└── my folder
    └── more
        └── file
Documents/
└── my folder
    ├── folder
    └── more

5 directories, 1 file
$ SEARCH=(D*/my\ folder)
$ find "${SEARCH[@]}" 
Desktop/my folder
Desktop/my folder/more
Desktop/my folder/more/file
Documents/my folder
Documents/my folder/more
Documents/my folder/folder

(*) expande en una matriz de cualquier coincide con el comodín. Y "${SEARCH[@]}" se expande en todos los elementos de la matriz ([@]), con cada uno individualmente citado.

Aunque tarde, me doy cuenta de que encontrar en sí mismo debería ser capaz de esto. Algo así como:

find . -path 'D*/my folder/more/'

0voto

rudders93 Puntos 58

Por fin he encontrado la respuesta.

Agregar una barra diagonal inversa a todos los espacios:

SEARCH='te*/my files/more'
SEARCH=${SEARCH// /\\ }

En este punto, SEARCH contiene te*/my\ files/more.

A continuación, utilice eval.

eval find ${SEARCH} -print

Es así de simple! El uso de eval omite la interpretación que ${SEARCH} es de una variable.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: