Algo que creo que debo saber con certeza: si lo hago ls <something>
, ¿ rm <something>
eliminaré exactamente los mismos archivos que se ls
muestran? ¿Hay alguna circunstancia en la que rm
pueda eliminar archivos que ls
no 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:
ls
no 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!
rm
no tenga una--dry-run
bandera ...find -delete
mejor querm
? Dices "Por eso" , pero no me queda completamente claro a qué se refiere. También tenga en cuenta que sufind
invocación eliminará todos los archivos de forma recursiva en el directorio actual, donderm
simplemente eliminará los archivos en el directorio inmediato. También-name *
es un no-op. En general, estoy bastante perplejo por su consejo ...find
es 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 ... -print
primero para confirmar qué archivos se eliminarán, y luegofind ... -delete
, seguirá eliminando los archivos creados entre los dos comandos. Si usa ambos-print
y-delete
no 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
ls
yrm
operar sobre los argumentos que se les pasan.Estos argumentos pueden ser un simple archivo, de modo
ls file.ext
yrm file.ext
operan 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 directory
se enumeran los contenidos del directorio, mientras querm directory
no va a funcionar como está (es decir,rm
sin banderas no pueden eliminar directorios, mientras que si lo hacerm -r directory
, de forma recursiva borra todos los archivos bajodirectory
y 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).txt
yrm $(rand).txt
, los argumentos son "iguales" pero los resultados son bastante diferentes.fuente
ls
vsrm *
donde hay archivos "ocultos" (punto), aunque incluso eso no es una comparación justa, ya que no escribíls *
. Pero norm
tiene 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 :)ls
contrarm -r
: el comandols <directory>
no mostrará los archivos ocultos en el interior del directorio, perorm -r <directory>
será eliminar incluso los archivos ocultos.ls
no los enumerará (a menos que tenga un aliasls -a
), yrm *
no los eliminará (a menos que hayadotglob
configurado).Si está pensando en algo como
ls foo*.txt
vs.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,
ls
enumeraría su contenido, perorm
no lo eliminaría. Eso generalmente no es un problema, yarm
que 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, yls
llevarían-r
a significar "orden inverso", mientras querm
llevaría-r
a 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é
rm
yls
podemos lidiar con ellos mismos. Al menos un caso dondels
se mostrará lorm
que no se puede eliminar involucra permisos de directorio, y el otro - directorios especiales.
y..
.Permisos de carpeta
rm
es 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 :rm
puede 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/echo
menos que sea el propietario/bin
o 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, perorm
no está permitido:fuente
Si escribe
ls *
y luegorm *
, es posible que elimine más archivos de losls
mostrados; podrían haberse creado en el pequeño intervalo de tiempo entre el finalls
y 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 quels
se mostrará y lo querm
funciona, 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 surm
comando.fuente
printf "%s\n" *
para obtener una visión inequívoca de los nombres de archivo con espacios. (O%q
en 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 porls
yrm
.fuente
No son casos extremos donde lo que
ls
muestra que no es lorm
elimina. Uno bastante extremo, pero afortunadamente benigno, es si el argumento que pasa es un enlace simbólico a un directorio:ls
le mostrará todos los archivos en el directorio de enlaces simbólicos, mientrasrm
que eliminará el enlace simbólico, dejando intacto el directorio original y su contenido:fuente
ln -s $HOME some_link; ls some_link
salidassome_link@
para mí, pero me hels
aliasls -F
. Aparentemente,-F
cambia el comportamiento para mostrar el enlace en lugar de desreferenciarlo. No esperaba eso.ls -l
por ejemplo, apunta al enlace, no al destino ... tiene que haber formas de inspeccionar el enlace en sí.ls
yrm
.ls some_link/
,ls -H some_link
ols -L some_link
, listará la ligada al directorio, incluso si se agrega-F
o-l
. Por el contrario (más o menos),-d
dice mirar un directorio en lugar de su contenido; compararls -l /tmp
yls -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
ls
en lugar dels -a
, sírm
se pueden eliminar los archivos ocultos que no han visto conls
y 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 -a
enumerará.
,..
,.test
ytest2
. Es posible que desee cambiar su ejemplo para usarls -A
, que enumera todo excepto.
y..
(es decir, solo.test
ytest2
).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
ls
si escribe?...? Tenga en cuenta que el
ls
comando 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 ells
comando 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.sh
para 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 *.txt
porque el mismo programa que realiza la eliminación le solicita cada archivo.
Esto es demasiado engorroso para un uso normal, y si alias
rm
arm -i
, usted se encontrará usando\rm
orm -f
con 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-i
opció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
ls
primero 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/baz
de izquierda a derecha.rm -rf /
es especial, perorm -rf /usr
no lo es! Omita la-rf
parte, o comience conls
, y solo agregue larm -rf
parte después de escribir la ruta.fuente