Tengo algunas carpetas con el \ncarácter de sus nombres.
por ejemplo:
$ ls
''$'\n''Test'
Eso se refiere a una carpeta con el nombre de la Prueba y una línea vacía antes de su nombre.
Entonces, cuando ejecuto algunos scripts como este, en su directorio principal:
while IFS= read -r d; do
rmdir $d
done < <(find * -type d)
Muestra:
rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Porque se ejecuta dos veces, una \ny otra Test, porque el nombre de la carpeta tiene dos líneas.
Entonces, ¿cómo puedo resolver este problema de modo que el script sepa \nTestque solo hay una carpeta?
command-line
bash
scripts
Tara S Volpe
fuente
fuente

-print0directiva find y la-dopción de lectura. Ver stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; donecomando tiene esta salidarmdir: failed to remove 'Test': No such file or directory.rmdir "$file"Respuestas:
Solo tiene un comando allí, por lo que es suficiente llamar
findcon una llamada de-execbanderarmdir:O use la
-deleteopción como enfind -type d -delete, pero no funcionará con directorios no vacíos. Para eso también necesitarás-emptybandera. Tenga en cuenta también,-deleteimplica-depthque se puede omitir. Por lo tanto, otra alternativa viable que mantiene todo como un solo proceso:Si el directorio no está vacío, use
rm -rf {} \;. Para aislar solo directorios con\nnombre de archivo, podemos combinar las citas ANSI-C de bash$'...'con la-nameopción:POSIX-ly, podríamos manejarlo de esta manera:
Vale la pena mencionar que si su objetivo es la eliminación de directorios, entonces
-deletees suficiente, sin embargo, si desea ejecutar un comando en el directorio, entonces-execes lo más apropiado.Ver también
findsalida?fuente
rm -rfcon cuidado . ; P ¿Nofindtiene una-deleteopción por cierto? Elimina los directorios vacíos y arroja errores para los que no están vacíos, comormdir- podría ser menos costoso.-deleteno eliminaré los directorios no vacíos. Por lo tanto, el uso cuidadoso derm -rffindcomandos sin ninguna carga útil destructiva (es decir, elimine el-deleteo-exec whatever \;) para verificar si la lista de archivos afectados es realmente correcta y no contiene cosas que no deberían eliminarse ...find. Use-exec rmdir {} +para agrupar múltiples argumentos en unarmdirlínea de comando. Y BTW " pero no funcionará con directorios no vacíos " también se aplicarmdir, por lo que en realidad no es una diferencia-delete. Es una diferencia derm -r.find -type d -empty -delete(-deleteimplica-depth)Podrías usar globos de concha en lugar de
find:El shell glob
*/coincide con todas las carpetas del directorio actual. Esta construcción de bucle for se encarga de dividir las palabras correctamente automáticamente.Tenga en cuenta que, dependiendo de sus opciones de shell, esto podría ignorar las carpetas ocultas (el nombre comienza con a.). Ese comportamiento se puede cambiar para que coincida con todos los archivos de la sesión actual con el comando
shopt -s dotglob.Además, no olvides citar siempre tus variables.
fuente
findhaceshopt -s globstary utilizando un**/*/glob en su lugar.Ambas respuestas escritas hasta ahora llaman
rmdiruna vez por directorio, pero comormdirpueden tomar múltiples argumentos, me pregunto: ¿no hay una manera más eficiente?Uno simplemente podría hacer
y esa es definitivamente la forma más fácil y eficiente, pero puede arrojar un error en el caso de muchos directorios (consulte ¿Cuál es la longitud máxima de los argumentos de la línea de comandos en gnome-terminal? ). Si desea que este enfoque funcione de forma recursiva, habilite la
globstaropción de shell conshopt -s globstary use en**/*/lugar de*/.Con GNU
find(y si no solo queremos usar-delete), podríamos hacerque construye la línea de comando "de la misma manera que
xargsconstruye sus líneas de comando" (man find). Sustituto-depthde-maxdepth 1si no se quiere que funcione de forma recursiva.Steeldriver explica una tercera y brillante forma de la OMI en esta respuesta :
Esto utiliza el shell incorporado
printfpara construir una lista de argumentos delimitada por cero, esta lista se canaliza axargslas llamadasrmdirexactamente con la frecuencia necesaria. Puede hacer que funcione recursivamente conshopt -s globstary en**/*/lugar de*/lo anterior.fuente
findes recursivo, pero el bucle del OP no lo es. Para replicar ese comportamiento, usefind -maxdepth 1 -type d -exec rmdir {} +. (-depthes redundante en ese caso). Buen trucoprintfpara emularfind -print0, no lo había visto antes.lsy elwhilebucle, eché de menos que estaban redirigiendo desde una sustitución de proceso enfindlugar de conectarselsal bucle y simplemente no lo mostraban por alguna razón. Esofind *está realmente enterrado. Sí, es recursivo y fallará si hay demasiadas entradas de directorio en el directorio, incluidas las que no son directorios porque no se usa*/.find .sería mucho mejor, porquefindes más rápidostatque la expansión global de bash.