En un script que uso find
para recopilar algunos archivos en el directorio actual, como en
$ find . -name "*.h"
./foo.h
Ahora me gustaría que solo salga foo.h
, sin el ./
prefijo. Pensé que la cadena vacía ""
indicaba el directorio actual en los comandos del shell. Pero esto da:
$ find "" -name "*.h"
find: ftsopen: No such file or directory
Entonces me equivoqué. Ahora mi pregunta es ¿cuándo/cómo/dónde/... una "cadena vacía (?)" indica el directorio actual en los comandos que esperan un nombre de archivo o una ruta de acceso? ¿Existe una explicación clara y esclarecedora?
Una pregunta secundaria es si el problema de búsqueda anterior se puede resolver de manera simple, sin manipulación de cadenas como ${parameter#word}
or cut
or sed
.
Respuesta1
Hace mucho tiempo (en 7ma edición, 32V, 4.2BSD, 4.3BSD), en el nivel de llamada al sistema, una ruta de acceso de longitud cero indicaba el directorio de trabajo actual (cuando se usaba para realizar búsquedas; no se permitía al intentar crear o eliminar un archivo o directorio). En Sistema III, fue un error utilizar una ruta de longitud cero en todas las circunstancias, y elestándar POSIXtiene esto que decir sobre la resolución de nombres de rutas:
Un nombre de ruta nulo no se resolverá exitosamente.
Respuesta2
Puedes usar:
find * -name "*.h"
Tenga en cuenta que los archivos en el directorio actual cuyo nombre comience con .
se omitirán, y los archivos cuyo nombre comience con -
serán interpretados como opciones find
y causarán estragos, por lo que este no es un equivalente general a find . …
.
La ausencia de una cadena que termine en " /
" como parte de un nombre de archivoimplicael directorio actual, pero eso no significa que el directorio actual seadenotadopor una cadena vacía (que podría decirse que no es lo mismo que la ausencia de una cadena, aunque podría verse igual cuando se imprima).
Respuesta3
En general, la cadena vacía no indica el directorio actual, ni para comandos de shell ni en llamadas al sistema.Lo hizo en algunos sistemas más antiguos, pero no en sistemas compatibles con POSIX..
Ocasionalmente encontrará un programa que usa el directorio actual cuando pasa una cadena vacía y el programa espera un nombre de directorio. Esto a veces es deliberado y, a veces, un efecto secundario de anteponer la ruta absoluta del directorio actual cuando la cadena dada no comienza con una barra.
Lo mejor para ti sería dejar el ./
. No hace ningún daño.
Si la lista de archivos es para
find . … | sed 's!^\./!!'
Tenga en cuenta que esto altera algunos nombres de archivos que contienen nuevas líneas. Por lo general, esto no es un problema para el consumo humano y la salida de find
no es adecuada para el consumo de programas ya que es ambigua. Si está utilizando -print0
, que es adecuado para el consumo de programas, probablemente no le importe el ./
prefijo de todos modos.
Puedes utilizarlo find * …
en lugar de find . …
, pero ten en cuenta que find *
tiene una serie de defectos que lo hacen inadecuado en general:
.
se omite..
Se omiten todos los archivos punto (archivos cuyo nombre comienza con o ..`).- Si hay un nombre de archivo en el directorio actual cuyo nombre comienza con
-
(o un archivo llamado!
o(
...), será interpretado como una opción o predicado porfind
.
El primer punto no importa si su filtro excluye el directorio actual. Para el segundo punto, puede usar los patrones ..?* .[!.]* *
para que coincidan con todos los archivos en el directorio actual, pero deberá verificar si cada patrón coincide con al menos un archivo y omitirlo si no es así. Esto es posible pero muy engorroso. El último punto es un tapón. Por lo tanto, find *
puede ser adecuado para un uso rápido en la línea de comandos, pero no lo use en un script.
Un enfoque alternativo es utilizar la función globbing recursiva del shell, por ejemplo
printf '%s\n' **/*.h
Esto debe activarse shopt -s globstar
en bash y set -o globstar
en ksh93, y no existe en un shell POSIX básico como dash. Los archivos Dot no se recorrerán de forma predeterminada; para incluirlos, primero haga que globbing no ignore los archivos dot en shopt -s dotglob
bash o FIGNORE='@(.|..)'
ksh93. Además, si no hay coincidencias, este comando imprime el patrón; ejecute shopt -s nullglob
bash para imprimir una línea vacía y use el patrón ~(N)**/*.h
en ksh.
En zsh, el globbing recursivo está activado de forma predeterminada. Utilice el calificador glob D
para incluir archivos de puntos e N
imprimir una línea vacía si no hay coincidencias (de forma predeterminada, zsh genera un error si un patrón no coincide con ningún archivo). Puedes usar printf
como arriba o
print -rl -- **/*.h(DN)
Respuesta4
Hay varios trucos que puedes usar para obtener el resultado de la búsqueda sin el encabezado ./
:
Utilice la opción de buscar
-printf
y dígale que solo imprima%f
. Verman find
:%f Nombre del archivo con todos los directorios principales eliminados (solo el último elemento).
Por ejemplo:
find . -name "*.h" -printf "%f\n"
Analizar la salida:
find . -name "*.h" | sed 's#^./##'
-
find * -name "*.h"
En cuanto a su otra pregunta, la cadena vacía nunca indica el directorio actual. Es solo que varios programas toman el directorio actual como predeterminado, por lo que cuando los ejecuta sin argumentos, se ejecutan en el directorio actual.