2010-11-26 23 views
8

find interpreta un guion al comienzo de un nombre de archivo como el inicio de una opción. Usar el conocido truco -- no funciona, ya que las opciones están después del nombre del archivo, las citas no tienen ningún efecto y tampoco funciona el reemplazo del primer guión con \-. A menudo se anima a los usuarios a que precedan dichos nombres de archivo con ./, pero ¿qué puedo hacer si no sé si la ruta dada será absoluta o relativa?buscar en el directorio que comienza con el guión

Editar: Una solución es find "$(readlink -f -- "$test_filename")", pero es fea. Alguna mejor idea?

Editar 2: Gracias por las sugerencias. Aquí están los dos guiones que resultaron de este esfuerzo: safe-find.sh; safe-count-files.sh

Respuesta

3

esto puede parecer un poco barato, pero realmente recomiendo la solución readlink que se haya descubierto. De acuerdo con la Unix standard,

El primer argumento que comienza con un '-' (...) y todos los argumentos posteriores deberán ser interpretado como una expresión

por lo -- se de hecho no funciona. La solución de thkala también puede funcionar, pero me parece menos legible. Sin embargo, puede ser más rápido si realiza muchas invocaciones find.

+0

Mi respuesta antes de la edición del OP hubiera de hecho, implicó readlink porque es menos esotérico que mi primer oneliner. Una desventaja es que lanza dos procesos más (un shell bifurcado y un readlink) y que si tiene múltiples directorios como argumentos para encontrar, aplicando readlink a todos ellos requerirá al menos un bucle y algunos trucos. – thkala

+0

@thkala: Me di cuenta de eso. '$ (exec readlink -f -" $ file ")' previene una de las bifurcaciones, en el gasto de legibilidad –

+0

@larsmans: la respuesta de thkala tiene la ventaja de funcionar en sistemas que no tienen 'readlink -f' (solo GNU, NetBSD y OpenBSD lo tienen). – Gilles

5

Si está en una secuencia de comandos, siempre puede verificarlo. P.ej. para bash, ksh o zsh:

if [[ "$DIR" = -* ]]; then 
    find ./"$DIR" 
else 
    find "$DIR" 
fi 

En una forma más concisa (para bash, ksh93 o zsh):

find "${DIR/#-/./-}" 

incluso se puede hacer esto con los parámetros de un guión, si están se supone que todos los directorios:

find "${@/#-/./-}" 
+0

Tenga en cuenta que 'if [" $ DIR = - *] 'podría hacer coincidir' DIR' con la cadena literal '- *' (si no hay archivos cuyo nombre comience con '-' en el directorio actual) o probablemente cause un error de sintaxis (si hay) – Gilles

+0

@Gilles: cierto ... No sé lo que me sucedió - Nunca uso 'test' o [en bash. – thkala

0

Utilice un pegote para capturar el tablero:

find . -name '[-]*' 

edición: actualizado para eliminar la expresión regular frase, y citar el pegote por lo que ha sido interpretado por encontrar, no bash (sólo afecta un poco de borde casos).

+1

Eso es globbing, no una expresión regular. –

+0

@DennisWilliamson Puede ser globbing, pero también es definitivamente una expresión regular. Hay una clase de personaje (trivial), hay catenation, y hay una estrella de Kleene. Si la clase de personaje tuviera un personaje más, habría alternancia, y tendría todas las cosas. Sin embargo, le garantizo que, técnicamente, cualquier serie de caracteres es una expresión regular si la usa como uno solo. –

+2

@ParthianShot: el shell procesa todo de '[-] *' como un glob, no como una expresión regular. El asterisco aquí no es una estrella de Kleene, ya que no significa "cero o más". En un globo, significa "cualquier cosa" como un comodín. Aquí la expresión significa un guión seguido de cualquier secuencia en lugar de cero o más guiones. Sin embargo, debe citarse para evitar una expansión prematura. –

2

Esta es una forma que debería funcionar en todos los sistemas de tipo Unix, sin requisitos en un shell específico o en una utilidad no estándar¹.

case $DIR in 
    -*) DIR=./$DIR;; 
esac 
find "$DIR" … 

Si tiene una lista de directorios en sus parámetros posicionales y desea procesarlos, se vuelve un poco complicado. He aquí una solución POSIX sh:

i=1 
while [ $i -le $# ]; do 
    case $1 in 
    -*) x=./$1;; 
    *) x=$1;; 
    esac 
    set -- "[email protected]" "$x" 
    shift 
    i=$(($i + 1)) 
done 
find "[email protected]" … 

shells Bourne y otras implementaciones pre-sh POSIX carecen de la aritmética y set --, así que es un poco más feo.

i=1 
while [ $i -le $# ]; do 
    x=$1 
    case $1 in 
    -*) x=./$1;; 
    esac 
    set a "[email protected]" "$x" 
    shift 
    shift 
    i=`expr $i + 1` 
done 
find "[email protected]" … 

¹ readlink -f está disponible en GNU (Linux, Cygwin, etc.), NetBSD ≥4.0, OpenBSD ≥2.2, BusyBox. No está disponible (a menos que haya instalado herramientas GNU, y se ha asegurado de que estén en su PATH) en Mac OS X (a partir de 10.6.4), HP-UX (a partir de 11.22), Solaris (como de OpenSolaris 200906), AIX (a partir de 7.1).

Cuestiones relacionadas