Algo que creo que debo saber con certeza: si lo hago ls <something>, ¿ rm <something>eliminaré exactamente los mismos archivos que se lsmuestran? ¿Hay alguna circunstancia en la que rmpueda eliminar archivos que lsno se muestran? (Esto es en la fiesta 18.04)
Editar: gracias a todos los que respondieron. Creo que la respuesta completa es una combinación de todas las respuestas, por lo que he aceptado la respuesta más votada como "la respuesta".
Cosas inesperadas que he aprendido en el camino:
lsno es tan sencillo como podría pensar en el manejo de sus argumentos- En una instalación simple y sin complicaciones de Ubuntu, los alias .bashrc
ls - ¡No asigne un nombre a sus archivos que comiencen con un guión, ya que pueden parecer argumentos de comando, y nombrar a uno -r lo solicita!

rmno tenga una--dry-runbandera ...find -deletemejor querm? Dices "Por eso" , pero no me queda completamente claro a qué se refiere. También tenga en cuenta que sufindinvocación eliminará todos los archivos de forma recursiva en el directorio actual, dondermsimplemente eliminará los archivos en el directorio inmediato. También-name *es un no-op. En general, estoy bastante perplejo por su consejo ...findes porque puedes ejecutarlo, ver todos los archivos y luego ejecutar el mismo comando con-delete. Como ya vio los resultadosfind, no debería haber ambigüedad sobre lo que se eliminará (en realidad me gustaría escuchar más detalles sobre esto en forma de respuesta)-delete" - Pero, ¿cómo es eso mejor que ejecutarlols <filespec>, seguido derm <filespec>(que el OP ya sabe cómo hacerlo)?find ... -printprimero para confirmar qué archivos se eliminarán, y luegofind ... -delete, seguirá eliminando los archivos creados entre los dos comandos. Si usa ambos-printy-deleteno obtiene confirmación, solo un informe posterior al hecho de lo que se ha eliminado (y también podría usarrm -v).Respuestas:
Bueno, ambos
lsyrmoperar sobre los argumentos que se les pasan.Estos argumentos pueden ser un simple archivo, de modo
ls file.extyrm file.extoperan en el mismo archivo y el resultado es claro (lista el archivo / borrar el archivo).Si por el contrario el argumento es un directorio,
ls directoryse enumeran los contenidos del directorio, mientras querm directoryno va a funcionar como está (es decir,rmsin banderas no pueden eliminar directorios, mientras que si lo hacerm -r directory, de forma recursiva borra todos los archivos bajodirectoryy el propio directorio ).Pero tenga en cuenta que los argumentos de la línea de comandos pueden estar sujetos a la expansión del shell , por lo que no siempre se garantiza que se pasen los mismos argumentos a ambos comandos si contienen comodines, variables, salida de otros comandos, etc.
Como ejemplo extremo, piense
ls $(rand).txtyrm $(rand).txt, los argumentos son "iguales" pero los resultados son bastante diferentes.fuente
lsvsrm *donde hay archivos "ocultos" (punto), aunque incluso eso no es una comparación justa, ya que no escribíls *. Pero normtiene sentido por sí solo, por lo que todo es manzanas y naranjas realmente. Si he entendido bien, ese es el quid de tu respuesta, así que buen trabajo :)lscontrarm -r: el comandols <directory>no mostrará los archivos ocultos en el interior del directorio, perorm -r <directory>será eliminar incluso los archivos ocultos.lsno los enumerará (a menos que tenga un aliasls -a), yrm *no los eliminará (a menos que hayadotglobconfigurado).Si está pensando en algo como
ls foo*.txtvs.rm foo*.txt, entonces sí, mostrarán y eliminarán los mismos archivos. El shell expande el globo y lo pasa al comando en cuestión, y los comandos funcionan en los archivos enumerados. Uno los enumera, uno los elimina.La diferencia obvia es que si alguno de esos archivos fuera un directorio,
lsenumeraría su contenido, perormno lo eliminaría. Eso generalmente no es un problema, yarmque eliminaría menos de lo que se mostróls.El gran problema aquí proviene de ejecutar
ls *orm *en un directorio que contiene nombres de archivos que comienzan con un guión . Ellos se expandirían a las líneas de comandos de los dos programas como si las escribió por su cuenta, ylsllevarían-ra significar "orden inverso", mientras quermllevaría-ra significar una eliminación recursiva. La diferencia es importante si tiene subdirectorios de al menos dos niveles de profundidad. (ls *mostrará el contenido de los directorios de primer nivel, perorm -r *también todo pasará el primer subnivel).Para evitar eso, escriba globos permisivos con un signo
./que indique el directorio actual, y / o ponga un--para indicar el final del procesamiento de opciones antes del globo (es decir,rm ./*orm -- *).Con un glob como
*.txt, en realidad no es un problema ya que el punto es un carácter de opción no válido y causará un error (hasta que alguien expanda las utilidades para inventar un significado para él), pero de todos modos es más seguro ponerlo./allí.Por supuesto, también podría obtener resultados diferentes para los dos comandos si cambia las opciones de bloqueo del shell, o crea / mueve / elimina archivos entre los comandos, pero dudo que haya querido decir alguno de esos casos. (Tratar con archivos nuevos / movidos sería extremadamente complicado de hacer de forma segura).
fuente
Dejando a un lado el comportamiento de shell, centrémonos solo en qué
rmylspodemos lidiar con ellos mismos. Al menos un caso dondelsse mostrará lormque no se puede eliminar involucra permisos de directorio, y el otro - directorios especiales.y...Permisos de carpeta
rmes una operación en un directorio, porque al eliminar un archivo, está cambiando el contenido del directorio (o, en otras palabras, una lista de entradas de directorio, ya que el directorio no es más que una lista de nombres de archivo e inodos ). Esto significa que necesita permisos de escritura en un directorio. Incluso si es el propietario del archivo , sin permisos de directorio no puede eliminar archivos. Lo contrario también es cierto :rmpuede eliminar archivos que pueden ser propiedad de otros, si usted es el propietario del directorio.Por lo tanto, es muy posible que tenga permisos de lectura y ejecución en un directorio, lo que le permitirá atravesar el directorio y ver los contenidos muy bien, por ejemplo
ls /bin/echo, pero no puede hacerlo arm /bin/echomenos que sea el propietario/bino eleve sus privilegiossudo.Y verá casos como este en todas partes. Aquí hay uno de estos casos: https://superuser.com/a/331124/418028
Directorios especiales '.' y '..'
Otro caso especial es
.y..directorios. Si lo hacels .ols .., felizmente le mostrará el contenido, perormno está permitido:fuente
Si escribe
ls *y luegorm *, es posible que elimine más archivos de loslsmostrados; podrían haberse creado en el pequeño intervalo de tiempo entre el finallsy el inicio derm.fuente
/tmp, donde muchas aplicaciones pueden crear archivos temporales, por lo que siempre es una posibilidad en ambos comandos con*. Sin embargo, algunas aplicaciones también hacen que los archivos sean anónimosunlink(), manteniéndolos abiertos, por lo que puede mostrarsels *perorm *no capturarse.*la diferencia entre lo quelsse mostrará y lo quermfunciona, porque la lista de contenidos del directorio ha cambiado en el medio.ls *podría mostrar el nombre de archivo que ya no está.ls *yrm *no son responsables de expandir el glob - eso lo hace el shell antes de pasarlo al comando.Esto significa que puede usar cualquier comando con la lista de archivos expandida, por lo que usaría algo que haga lo menos posible.
Entonces, una mejor manera de hacer esto (o al menos, otra forma) es saltarse al intermediario.
echo *le mostrará exactamente lo que se pasaría a surmcomando.fuente
printf "%s\n" *para obtener una visión inequívoca de los nombres de archivo con espacios. (O%qen lugar de tratar con los saltos de línea y caracteres de control también, a expensas de los más feos de salida.)Qué tal si:
Básicamente, los comodines que se expanden a cosas que comienzan con
-(o cosas ingresadas manualmente que comienzan con-pero que se parece un poco más a una trampa) pueden interpretarse de manera diferente porlsyrm.fuente
No son casos extremos donde lo que
lsmuestra que no es lormelimina. Uno bastante extremo, pero afortunadamente benigno, es si el argumento que pasa es un enlace simbólico a un directorio:lsle mostrará todos los archivos en el directorio de enlaces simbólicos, mientrasrmque eliminará el enlace simbólico, dejando intacto el directorio original y su contenido:fuente
ln -s $HOME some_link; ls some_linksalidassome_link@para mí, pero me helsaliasls -F. Aparentemente,-Fcambia el comportamiento para mostrar el enlace en lugar de desreferenciarlo. No esperaba eso.ls -lpor ejemplo, apunta al enlace, no al destino ... tiene que haber formas de inspeccionar el enlace en sí.lsyrm.ls some_link/,ls -H some_linkols -L some_link, listará la ligada al directorio, incluso si se agrega-Fo-l. Por el contrario (más o menos),-ddice mirar un directorio en lugar de su contenido; compararls -l /tmpyls -ld /tmp.ls. Básicamente, se está mostrando por qué enumerar comportamientos con diferentes banderas no es digno de la incomodidad para esta pregunta ...Si lo hace solamente
lsen lugar dels -a, sírmse pueden eliminar los archivos ocultos que no han visto conlsy sin-a.Ejemplo:
De acuerdo a :
ls dir_test: solo mostrará test2ls -A dir_test: mostrará test2 + .testrm -r dir_test: eliminará todo (.test + test2)Espero que eso te ayude.
fuente
rm *no eliminará los archivos de puntos. Si lo hace,ls *también los mostrará.ls *no muestres archivos ocultos.ls -aenumerará.,..,.testytest2. Es posible que desee cambiar su ejemplo para usarls -A, que enumera todo excepto.y..(es decir, solo.testytest2).Ya hay muchas buenas respuestas, pero quiero agregar una visión más profunda.
Hágase la pregunta: ¿A cuántos parámetros se pasan
lssi escribe?...? Tenga en cuenta que el
lscomando no obtiene el*parámetro como si hay archivos a los que*se pueda expandir. En cambio, el shell primero realiza el bloqueo antes de invocar el comando, por lo que ellscomando realmente obtiene tantos parámetros como archivos que coinciden con el bloqueo. Para suprimir el globbing, cite el parámetro.Esto es cierto para cualquier comando:
echo *vsecho '*'.Hay un script, llámalo
countparams.shpara probar el efecto. Le indica cuántos parámetros pasó y los enumera.Hazlo ejecutable y ejecútalo
./countparams.sh *. ¡Aprende de su salida!fuente
El globo se expandirá de la misma manera las dos veces, si el contenido del directorio es el mismo en esos dos momentos diferentes.
Si realmente desea verificar qué se eliminará, úselo
rm -i *.txt. Le indicará por separado para cada archivo antes de (intentar) eliminarlo.Se garantiza que esto es seguro contra las condiciones de la carrera:
ls *.txt/ se crea un nuevo archivo /rm *.txtporque el mismo programa que realiza la eliminación le solicita cada archivo.
Esto es demasiado engorroso para un uso normal, y si alias
rmarm -i, usted se encontrará usando\rmorm -fcon bastante frecuencia. Pero vale la pena mencionar al menos que hay una solución para la condición de la carrera. (Incluso es portátil para sistemas que no son GNU: POSIXrm(1)especifica la-iopción ).Otra opción sería una matriz bash:,
to_remove=(*.txt)luego pídale al usuario que confirme (tal vez después de hacerlols -ld -- "${to_remove[@]}"), luegorm -- "${to_remove[@]}". Por lo tanto, la expansión global solo se realiza una vez, y la lista se pasa literalmente arm.Otra opción prácticamente utilizable es GNU
rm -I( página de manual ), que indica si se eliminan más de 4 elementos. (Pero no muestra la lista, solo el total). Lo usoalias rm='rm -I'en mi escritorio.Es una buena protección contra el regreso de los dedos gordos con un patrón medio tipado que coincide demasiado. Pero usar
lsprimero es generalmente bueno en un directorio de su propiedad, o en un sistema de usuario único, y cuando no hay procesos en segundo plano que puedan crear asincrónicamente nuevos archivos allí. Para protegerse contra los dedos gordos, no escribarm -rf /foo/bar/bazde izquierda a derecha.rm -rf /es especial, perorm -rf /usrno lo es! Omita la-rfparte, o comience conls, y solo agregue larm -rfparte después de escribir la ruta.fuente