Me preguntaba si usar rm $(ls)
para eliminar archivos (o rm -r $(ls)
para eliminar directorios también) era seguro. Porque en todos los sitios web, las personas ofrecen otras formas de hacerlo, aunque este comando parece mucho más fácil que otros comandos.
13
touch 'foo -r .. bar'
;rm $(ls)
; ¿A dónde fue mi directorio principal? Además, ¿qué tipo de alternativas estás viendo que son aún más complicadas que esta?rm *
es mucho más fácil de escribir y pensar, y más seguro (pero no perfectamente seguro; vea la respuesta de Dennis).ls
puede variar entre implementaciones y, por lo tanto, no es estándar. Dependiendo de lo que necesite, considere alternativas comofind
ystat
. Debe usarlols
solo para consumo humano, nunca para usarlo con otros comandos o en scripts.Respuestas:
¿Qué se pretende hacer con esto?
ls
enumera archivos en el directorio actual$(ls)
sustituye la salida dels
lugares que como argumento pararm
rm $(ls)
está destinado a eliminar todos los archivos en el directorio actualQué está mal con esta imagen ?
ls
no puede manejar correctamente caracteres especiales en el nombre del archivo. Los usuarios de Unix generalmente recomiendan usar diferentes enfoques . También lo he demostrado en una pregunta relacionada sobre el conteo de nombres de archivos . Por ejemplo:Además, como se menciona correctamente en la respuesta de Denis, un nombre de archivo con guiones iniciales podría interpretarse como un argumento para
rm
después de la sustitución, lo que anula el propósito de eliminar el nombre de archivo.Que funciona
Desea eliminar archivos en el directorio actual. Entonces usa glob
rm *
:Puedes usar el
find
comando. Esta herramienta se recomienda con frecuencia para algo más que el directorio actual: puede atravesar recursivamente todo el árbol de directorios y operar archivos a través de-exec . . .{} \;
Python no tiene problemas con los caracteres especiales en los nombres de archivo, por lo que podríamos emplear eso también (tenga en cuenta que este es solo para archivos, deberá usar
os.rmdir()
yos.path.isdir()
si desea operar en directorios):De hecho, el comando anterior podría convertirse en función o alias
~/.bashrc
por brevedad. Por ejemplo,Perl versión de eso sería
fuente
"$(ls)"
ejemplo solo funciona si solo hay un archivo en el directorio. También podría usar la finalización de tabulación para expandir el nombre de archivo, ya que es la única finalización.ls
entonces :) Lo$(ls)
para deshabilitar la división de palabras, o deja que ocurra la división de palabras (con resultados desastrosos). La única forma limpia de pasar una lista de múltiples cadenas sin tratar los datos como código es con variables de matriz, o con\0
un separador, pero el shell en sí mismo no puede hacer eso. TodavíaIFS=$'\n'
es el menos peligroso, pero no puede igualarfind -print0 | xargs -0
. Ogrep -l --null
. O evitas todo el problema con cosas comofind -exec rm {} +
. (Tenga en cuenta que+
para pasar varios argumentos a cada invocación de rm; MUCHO más eficiente).IFS=$'\n'
también fallará en este caso, ya que tengo una nueva línea en el nombre del archivo, por lo que la división de palabras lo tratará como dos nombres de archivo en lugar de uno. La extraña razón, sin embargo, es el hecho de que con el valor predeterminadoIFS
que es espacio, tabulación, nueva línea, originalrm "$(ls)"
también debería fallar, debería tratar como dije el nombre de archivo como dos separados, pero no fue así. Me suelen utilizarfind
con-exec
ofind . . .-print0 | while IFS= read -d'' FILENAME ; do . . . done
estructura para hacer frente a los nombres de archivo. O uno podría usarpython
, he agregado un ejemplo de eso."$(ls)"
siempre se expande a un argumento porque las comillas protegen la expansión de$(ls)
la división de palabras. Justo como lo protegen"$foo"
.No, no es seguro, y la alternativa de uso común
rm *
no es mucho más segura.Hay muchos problemas con
rm $(ls)
. Como otros ya han cubierto en sus respuestas, la salida dels
se dividirá en los caracteres presentes en el separador de campo interno .En el mejor de los casos, simplemente no funciona. En el peor de los casos, pretendía eliminar solo archivos (pero no directorios), o eliminar selectivamente algunos archivos con
-i
, pero hay un archivo con el nombrec -rf
en el directorio actual. Veamos qué pasa.Se
rm -i $(ls)
suponía que el comando debía eliminar solo los archivos y preguntar antes de eliminar cada uno, pero el comando que finalmente se ejecutó decíaentonces hizo algo completamente diferente.
Tenga en cuenta que
rm *
solo es marginalmente mejor. Con la estructura de directorios como antes, se comportará como se pretende aquí, pero si tiene un archivo llamado-rf
, todavía no tiene suerte.Hay varias alternativas mejores. Los más fáciles implican solo rm y globbing.
El comando
funcionará exactamente como se pretendía, donde
--
indica que todo después de esto no debe interpretarse como una opción.Esto ha sido parte de las pautas de sintaxis de la utilidad POSIX durante más de dos décadas. Está muy extendido, pero no debes esperar que esté presente en todas partes.
El comando
hace que el globo se expanda de manera diferente y, por lo tanto, no requiere soporte de la utilidad llamada.
Para mi ejemplo de arriba, puede ver el comando que finalmente se ejecutará anteponiendo echo .
El encabezado
./
evita que rm trate accidentalmente cualquiera de los nombres de archivo como opciones.fuente
rm
. +1touch 'foo -rf .. bar
. No creo que un atacante pueda llegar más alto que el directorio padre, a menos que podamos producir un separador de ruta enls
la salida de.rm: refusing to remove '.' or '..' directory: skipping '..'
o algo similar al intentar eliminar el directorio principal.