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 ""
denotaba el directorio actual en los comandos de 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 (?)" Denota el directorio actual en los comandos que esperan un nombre de archivo o un nombre de ruta? ¿Hay una explicación clara y esclarecedora?
Una pregunta secundaria es si el hallazgo de nitpicking anterior se puede resolver simplemente, sin manipulación de cadenas a la ${parameter#word}
o cut
o sed
.
find
tiene el parámetro -printf para manipular cómo se muestran los resultados.find . -name '*.h' -printf '%P\n'
eliminará el./
prefijo Mira lo quefind . -name '*.h' -print
hace.-printf
opción. FWIW,strings
en mi hallazgo da@(#)PROGRAM:find PROJECT:shell_cmds-175
?!?Respuestas:
Hace mucho tiempo (en la 7ª edición , 32V , 4.2BSD , 4.3BSD ), en el nivel de llamada del sistema, un nombre de ruta de longitud cero indicaba el directorio de trabajo actual (cuando se usaba para la búsqueda; no se permitía al intentar crear o eliminar un archivo o directorio). En el Sistema III , fue un error usar un nombre de ruta de longitud cero en todas las circunstancias, y el estándar POSIX tiene esto que decir sobre la resolución del nombre de ruta:
fuente
dir/
es casi lo mismo quedir/.
Puedes usar:
Tenga en cuenta que los archivos en el directorio actual cuyo nombre comience con
.
se omitirán, y los archivos cuyo nombre comience con-
se interpretarán como opcionesfind
y causarán estragos, por lo que esto no es un equivalente general defind . …
.La ausencia de una cadena que termine en "
/
" como parte de un nombre de archivo implica el directorio actual, pero eso no significa que el directorio actual se denota por una cadena vacía (que posiblemente no sea lo mismo que la ausencia de una cadena, aunque podría verse igual cuando se imprime).fuente
En general, la cadena vacía no denota el directorio actual, ni a los comandos de shell ni a las llamadas del sistema. Lo hizo en algunos sistemas más antiguos, pero no en los 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 es un efecto secundario de anteponer la ruta absoluta del directorio actual cuando la cadena dada no comienza con una barra inclinada.
Lo mejor para ti sería dejar el
./
. No hace ningún daño.Si la lista de archivos es para
Tenga en cuenta que esto altera algunos nombres de archivo que contienen nuevas líneas. Esto generalmente no es un problema para el consumo humano, y la producción de
find
no es adecuada para el consumo del programa, ya que es ambigua. Si está utilizando-print0
, que es adecuado para el consumo del programa, probablemente no le importe el./
prefijo de todos modos.Puede usar en
find * …
lugar defind . …
, pero tenga en cuenta quefind *
tiene una serie de defectos que lo hacen inadecuado en general:.
se omite..
Se omiten todos los archivos de puntos (archivos cuyo nombre comienza con o ..`).-
(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 hacer coincidir todos los archivos en el directorio actual, pero deberá verificar si cada patrón coincide con al menos un archivo y omitirlo si no lo hace. Esto es posible pero muy engorroso. El último punto es un tapón. Porfind *
lo tanto, puede ser adecuado para el uso rápido de la línea de comandos, pero no lo use en un script.Un enfoque alternativo es utilizar la función de engrosamiento recursivo del shell, p. Ej.
Esto debe activarse
shopt -s globstar
en bash yset -o globstar
en ksh93, y no existe en un shell POSIX básico como el guión. Los archivos de puntos no se atravesarán de forma predeterminada; para incluirlos, primero haga que el globbing no ignore los archivos de puntosshopt -s dotglob
en bash oFIGNORE='@(.|..)'
en ksh93. Además, si no hay coincidencias, este comando imprime el patrón; ejecutashopt -s nullglob
en bash para imprimir una línea vacía en su lugar, y usa el patrón~(N)**/*.h
en ksh.En zsh, el bloqueo recursivo está activado de forma predeterminada. Use el calificador global
D
para incluir archivos de puntos eN
imprimir una línea vacía si no hay coincidencias (de manera predeterminada, zsh arroja un error si un patrón no coincide con ningún archivo). Puedes usarprintf
como arriba ofuente
find *
son nuevos para mí, y algunos son aterradores!No puedo pensar en ningún ejemplo donde la cadena vacía denota el directorio actual
.
. Puede estar pensando en invocaciones comols
, pero eso se debe a quels
asume el directorio actual si no se proporciona ningún parámetro, y de hecho no tomará la cadena vacía:fuente
PATH
componente.Hay varios trucos que puede usar para obtener la salida de find sin el líder
./
:Use la
-printf
opción de búsqueda y dígale que solo imprima%f
. Verman find
:Por ejemplo:
Analiza la salida:
Truco de @ Anthon
En cuanto a su otra pregunta, la cadena vacía nunca denota 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.
fuente
find
. O%P
./
find * -name '*.h'
encontraráfoo/.bar.h
, pero no.bar.h
en el directorio actual.Si los archivos están en el directorio actual, puede usar
ls
:Si desea los archivos en subdirectorios también y solo necesita el nombre de archivo, puede hacer algo como:
Hay comandos que obtendrán la ausencia de una cadena como el directorio actual, pero básicamente porque obtendrán el directorio actual por defecto si no se ingresa nada. El
.
siempre denota el directorio actual (y..
el directorio padre)fuente
find
solución elimina todos los componentes del directorio