Tengo algunas carpetas con el \n
cará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 \n
y 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 \nTest
que solo hay una carpeta?
command-line
bash
scripts
Tara S Volpe
fuente
fuente
-print0
directiva find y la-d
opción de lectura. Ver stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done
comando 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
find
con una llamada de-exec
banderarmdir
:O use la
-delete
opción como enfind -type d -delete
, pero no funcionará con directorios no vacíos. Para eso también necesitarás-empty
bandera. Tenga en cuenta también,-delete
implica-depth
que 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\n
nombre de archivo, podemos combinar las citas ANSI-C de bash$'...'
con la-name
opción:POSIX-ly, podríamos manejarlo de esta manera:
Vale la pena mencionar que si su objetivo es la eliminación de directorios, entonces
-delete
es suficiente, sin embargo, si desea ejecutar un comando en el directorio, entonces-exec
es lo más apropiado.Ver también
find
salida?fuente
rm -rf
con cuidado . ; P ¿Nofind
tiene una-delete
opció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.-delete
no eliminaré los directorios no vacíos. Por lo tanto, el uso cuidadoso derm -rf
find
comandos sin ninguna carga útil destructiva (es decir, elimine el-delete
o-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 unarmdir
lí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
(-delete
implica-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
find
haceshopt -s globstar
y utilizando un**/*/
glob en su lugar.Ambas respuestas escritas hasta ahora llaman
rmdir
una vez por directorio, pero comormdir
pueden 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
globstar
opción de shell conshopt -s globstar
y 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
xargs
construye sus líneas de comando" (man find
). Sustituto-depth
de-maxdepth 1
si 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
printf
para construir una lista de argumentos delimitada por cero, esta lista se canaliza axargs
las llamadasrmdir
exactamente con la frecuencia necesaria. Puede hacer que funcione recursivamente conshopt -s globstar
y en**/*/
lugar de*/
lo anterior.fuente
find
es recursivo, pero el bucle del OP no lo es. Para replicar ese comportamiento, usefind -maxdepth 1 -type d -exec rmdir {} +
. (-depth
es redundante en ese caso). Buen trucoprintf
para emularfind -print0
, no lo había visto antes.ls
y elwhile
bucle, eché de menos que estaban redirigiendo desde una sustitución de proceso enfind
lugar de conectarsels
al 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, porquefind
es más rápidostat
que la expansión global de bash.