Evite que el usuario escriba espacio accidental entre rm y comodín

29

Intención:

rm -rf string*

Problema:

rm -rf string *

El primer caso es un uso legítimo y común de rm, un error tipográfico pequeño puede causar muchos problemas en el segundo caso. ¿Existe una manera simple de protegerse de manera inteligente contra un comodín inicial o final accidental?

bobdole
fuente
8
Con un shell reciente y bien configurado ( zsho bash) prefiero tomar el hábito de presionar la tecla tab (para activar la finalización automática) antes de presionar la tecla de retorno
Basile Starynkevitch
2
touch -- -icreará un archivo -ique se pasará rmcomo parámetro -icuando incluya un comodín en sus argumentos.
Restablece a Monica - M. Schröder el
@ MartinSchröder: si se encuentra en el directorio donde existe el archivo.
Pausado hasta nuevo aviso.
@ MartinSchröder Eso solo funcionará si escribe rm *. Si tipifica rm name *, se expandirá a rm name -i other names. -ino se procesará como una opción porque no está antes de los nombres de archivo.
Barmar
1
Por lo general, un usuario solo hace esto una vez.
tedder42

Respuestas:

37

Se DEBUGpodría escribir una trampa para cancelar los comandos que parecen sospechosos. Lo siguiente, o un código similar, se puede agregar a su ~/.bashrc:

shopt -s extdebug
checkcommand() {
  if [[ $BASH_COMMAND = 'rm -r'*' *' ]]; then
    echo "Suppressing rm -r command ending in a wildcard" >&2
    return 1
  fi
  # check for other commands here, if you like
  return 0
}
trap checkcommand DEBUG

Ajusta la lógica al gusto.

(En realidad, no espero que este enfoque sea útil, demasiadas formas de desordenar un comando destructivamente para encontrarlos probando uno por uno, pero proporciona una respuesta literal a la pregunta).

Charles Duffy
fuente
47

No hay forma de un sistema totalmente a prueba de balas. Y agregando "¿Estás seguro?" Las preguntas sobre las cosas son contraproducentes y conducen a "Por supuesto que estoy seguro". Reacciones de kneejerk.

Un truco que aprendí de un libro en años pasados ​​es hacer primero ls -R blah*, hacer rm -fr blah* si y solo si la lista que apareció apareció lo que quería.

Es bastante fácil hacer el lscomando primero, luego , eliminar ls -Ry reemplazar con rm -fr.

La última pregunta es: "Si la información fue valiosa para usted, ¿dónde está su respaldo?"

asesino
fuente
44
En lugar de la flecha hacia arriba, puede usar ^ls -R^rm -rf^y establecer como un alias
exussum
FWIW, esto es ls -Rlo que básicamente hago todo el tiempo, pero es tan instintivo en este punto que se me escapó la mente consciente cuando me formé por respuesta. Entonces +1 para eso.
JakeGould
Esto también tiene la ventaja de que no hará daño si presiona la tecla Intro, o presiona el mouse y pega algo con líneas nuevas. A veces ingreso las cosas en un orden menos eficiente solo para mayor seguridad, por ejemplo cat > .log, luego regreso y pego o tiro el nombre del archivo antes del .log. Entonces, en ningún momento tengo > valuablefileen el cmdline.
Peter Cordes
Uso rm con alias rm -i, por lo que a menudo solo redacto mi comando rm y luego pongo un \ al comienzo de la línea. ( \rmevita la expansión de alias para rm, ya que parte de la palabra fue citada). Si necesitaba un -ro -f, sí, a veces empiezo con en lslugar de rm, o simplemente dejo la -rfparte. (editar, ¿cómo se obtiene un formato de código de barra invertida? bquote bslash bslash bquote falla.
Peter Cordes
8

¿Puedes entrenarte para usar, por ejemplo, rmrfen lugar de rm -rf?

Si es así, esta función bash le brindará la oportunidad de ver qué sucedería realmente antes de confirmar el comando:

rmrf() { echo rm -rf "$@"; read -p "Proceed (y/N)? "; [ "${REPLY,,}" = y ] && rm -rf "$@"; }

Para que esta función sea permanente, agregue esta línea al ~/.bashrcarchivo en cada computadora que use.

Comparación con el rmalias común

Es común definir un alias:

alias rm='rm -i'

Esto tiene dos limitaciones:

  1. Si depende de este alias, se sorprenderá cuando esté en una máquina o en un entorno que no lo tenga. Por el contrario, intentar ejecutar rmrfen una máquina sin esa función devolverá un inofensivo command not found.

  2. Este alias no es de ayuda en su caso porque la -fopción que proporciona en la línea de comando anula la -iopción en el alias.

John1024
fuente
44
No es una mala idea. Pero depende de que esta función esté instalada y disponible en cualquier sistema que este usuario esté utilizando. Entonces, digamos que inician sesión en un servidor remoto para trabajar y ejecutan el rm -rfcomando incorrecto , ¿qué sucede? Crear pseudo funciones como esta en última instancia solo complica una solución simple: solo tenga más cuidado y comprenda qué son los permisos.
JakeGould
44
@JakeGould Y no use rm -f a menos que realmente lo necesite .
un CVn el
1
¿Por qué molestarse rmrf, en lugar de simplemente crear una función de shell rmque verifique los argumentos -ro -rf, y promulgue una lógica especial en ese caso, de lo contrario, llame directamente command rm "$@"para invocar el rmcomando real ?
Charles Duffy
3
Utiliza un nombre diferente para no dispararse en el pie cuando su anulación no está allí. Y estoy de acuerdo con @ MichaelKjörling, no necesitas -fsi no tienes -i. Dejarlo apagado -fle da una advertencia adicional antes de eliminar un archivo de solo lectura, por ejemplo.
Peter Cordes
6

Si estoy en una situación en la eliminación de los archivos incorrectos es un acuerdo muy grande, una de las cosas que he hecho es hacer una carpeta papelera, como mkdir trashcan, y luego tengo un script rmTrashcanque tiene una rm -rf trashcan/*o rm -rf *o similares, escrito con mucho cuidado y comprobado varias veces.

De esa manera, si cometo un error, el error está en un mvcomando, no en un rmcomando. Una vez que hago una lsy persuadido de exactamente lo que estoy borrando, una rmTrashcanrealidad hace el trabajo sucio con seguridad.

También fue tremendamente conveniente para una situación en la que tuve que eliminar copias de seguridad. Podía mvun mes entero de copias de seguridad en la papelera, mvlas pocas que quería mantener (1 de mes, 15 de mes) de nuevo en las copias de seguridad, luego rmTranshcanel resto. Hacer un comando similar es difícil de hacer rmpor sí solo, y hacerlo de esta manera me permitió tener lslas copias de seguridad para estar seguro de qué archivos estoy dejando atrás (en lugar de simplemente enumerar los archivos que pretendo eliminar)

Cort Ammon - Restablece a Monica
fuente
4

En lugar de molestarse con dos comandos ( lsy rm), creo que es una forma más simple y fácil de usar find:

find . -maxdepth 1 -name "string*" -delete

Si accidentalmente escribe "string *", eliminará los archivos con el nombre string charsy string letters(que es lo que quería de todos modos), pero no tomará todos los archivos como *en un shell.

Además, puede dejar de -deletever los archivos que va a eliminar, luego presionar la flecha hacia arriba y escribir -deletemás fácilmente que escribir ^ls -R^rm -rfu otras tonterías.

niñera
fuente
A findrealizará una búsqueda anidada de archivos que coincidan en lugar de solo los parámetros explícitos declarados en la línea de comandos. Creo que esto pierde la marca. Aunque podría estar equivocado.
Killermist
3

¿Existe una manera simple de protegerse de manera inteligente contra un comodín inicial o final accidental?

Realmente no. Se propone en otra respuesta que podría crear un comando personalizado para agregar un aviso antes de ejecutar una tarea. Pero el problema con este comando personalizado es que debe instalarse conscientemente en los sistemas en los que está trabajando. E incluso si está instalado, el problema es que tu reflejo de golpe ypara completar la tarea podría entrar en juego.

Lo que significa que todo esto es un problema de interfaz de usuario, incluso si está en un nivel de línea de texto / comando. ¿Cuántas redes de seguridad esperas que haya para protegerte de hacer algo que no deberías? Es como un par de tijeras: si eres negligente y te resbalas y te cortas la mano mientras intentas cortar tela o papel, ¿quién tiene la culpa? O incluso semáforos y señales de alto: realmente no hay nada que impida que un conductor encienda un semáforo o ignore las señales de tránsito que no sea una aguda conciencia de lo que podría suceder si se involucran en un comportamiento tan arriesgado.

Dicho esto, la mejor solución realista radica en los permisos del sistema para usuarios y grupos. Esa es la mejor / única red de seguridad real para proteger a un usuario de sí mismo.

Si está trabajando en un sistema en el que es el único que accede a él, puede sentirse tentado a chmod 777todo, pero esa no es la forma en que se configura un sistema racional. En cambio, los permisos deberían ser algo así como 755para todos los directorios y 644para todos los archivos no ejecutables. Los archivos ejecutables deben ser 755al menos, pero tal vez incluso 744si solo desea que otros lean pero no ejecuten los archivos.

JakeGould
fuente
2

Intente componer su rmcomando inicial sin la -fbandera, sino con -iuna que rmle solicite cada archivo que intente eliminar. Para pequeñas eliminaciones recursivas, puede mantener presionada la ytecla, una vez que esté seguro de que el comando se ha escrito correctamente. Para eliminaciones grandes, puede abortar la operación y usar el historial de la línea de comandos para cambiar cuidadosamente el -ia -f.

Nevin Williams
fuente
En realidad, debe presionar y[RETURN]cada archivo, no hay nada que pueda mantener presionado con GNU rm. Editar -ies el camino a seguir, una vez que tenga el comando escrito correctamente. Luego obtienes un mensaje solo en un archivo de solo lectura, y tal vez otras cosas.
Peter Cordes
1
Solo utilícelo rm -Ipara que solo se solicite una vez, y solo para eliminaciones potencialmente peligrosas (es decir, de muchos archivos).
Nick Matteo
1
En foros menos constructivos, mi respuesta habría sido algo así como "Si su mecanografía / corrección de pruebas es tan mala, no tiene sentido usar 'rm -rf' con comodines". No conocía el interruptor -I ... debe haber sido introducido hace <20 años; sobre la última vez que hice 'man rm'. :)
Nevin Williams
2

rm tiene -iy -Imarcas para confirmar antes de cada eliminación. En el pasado, algunas distribuciones los activaron de manera predeterminada. Esta es una idea terrible. Dele al usuario demasiados cuadros de diálogo de confirmación para las operaciones normales y comenzarán a confirmarlos habitualmente. Esto simplemente cambia el requisito de "tener cuidado" (siempre una bandera roja) a un diálogo nuevo y más molesto. "Sí. Sí. Sí. ¡Sí! ¡SÍ! Maldita sea, estúpida computadora, simplemente borra los archivos SÍ SÍ SÍ SÍ - ¡MIERDA, NO QUIERO! Este es el problema de diálogo "Sí, pero no quise decir". Esta respuesta proporciona una explicación visual de por qué los cuadros de diálogo de confirmación llegan en el momento equivocado.

El tipo de error que describes es un deslizamiento , "la realización de una acción que no era lo que se pretendía". El usuario generalmente reconoce inmediatamente el error y sabe exactamente cómo solucionarlo. Desafortunadamente, Unix no le da la oportunidad al usuario, rm elimina el archivo inmediatamente. Todos los demás sistemas operativos resuelven este problema permitiendo que se eliminen las eliminaciones, al menos durante un tiempo, mediante el uso de la Papelera.

Hay varios sistemas de basura para Unix, y esta respuesta está llena de sugerencias .

La pregunta es alias rm o no alias rm. Pros aliasing rm ...

  1. No puede olvidarse de usar la alternativa rm.

Contras para aliasing rm ...

  1. Puede confiar en sistemas que no lo tienen.
  2. Puede causar problemas cuando el disco está casi lleno.
  3. Necesita infraestructura para vaciar periódicamente la basura.
  4. Debe asegurarse de no interferir con el comportamiento esperado de rm en los programas.
  5. Es posible que no emule completamente rm.

Si sigue demasiado lejos el primer argumento, termina usando vi (no vim, vi), csh (no tcsh, csh) y otras utilidades anticuadas porque están disponibles universalmente. Aún así, existe el peligro de personalizar en exceso su entorno. Prefiero llevar mis utilidades conmigo y hacer que sea lo más fácil posible. YMMV.

Dos y tres son problemas técnicos. Se pueden resolver con un ingenioso trabajo de segador que verifica el tamaño de la basura y limpia periódicamente las cosas, de forma similar a un tmpreaper . Esto puede ser un trabajo cron, o una versión más inteligente puede hacer uso de las diversas infraestructuras de eventos del sistema de archivos disponibles en muchas distribuciones Linux de escritorio. Esto no es simple, y aún más difícil de hacer de manera eficiente. Es mejor encontrar un sistema existente que tratar de hacer uno propio.

El cuarto puede tratarse haciendo que su nueva rm sea un alias de shell alias rm='trash', entonces no afectará a los programas.

El quinto es un problema que dejo para que el lector lo resuelva. rm no tiene muchos interruptores.

Schwern
fuente
Tengo alias rm -i, pero a menudo uso \rmpara obtener el comportamiento sin alias. Escribo rm -icada vez que estoy PLANEANDO para decir no a uno de los argumentos. A veces comienzo el comando con lsel comando, luego solo pongo el \ rm cuando termino. Así que no hay manera de que pueda presionar accidentalmente el retorno en rm -rf /lugar de/.../file
Peter Cordes
rm -Io rm --interactive=oncees mucho, mucho menos molesto que rm -i, y aún atrapa algo peligroso (solo aparece cuando hay más de 3 archivos, o si es recursivo, y solo UNA VEZ en vez de POR CADA ARCHIVO).
Nick Matteo
@Kundor Sí, y no cambia la ecuación. Probablemente aumenta la probabilidad de que el usuario lo ignore. El usuario tiene un objetivo: eliminar cosas. El mensaje dice "¿estás seguro de que deseas eliminar las cosas que me acabas de pedir que elimine?" El usuario todavía está obsesionado con el objetivo de eliminar cosas, sin verificar lo que se va a eliminar, por lo que dicen "sí" sin pensar. -ipodría darle tiempo al usuario para cambiar los objetivos. Esta respuesta a una pregunta relacionada lo expone todo.
Schwern
@Schwern: pero nadie puede vivir rm -idurante más de 30 segundos sin apagarlo. Mientras que rm -Isolo te avisa cuando es probable que te hayas equivocado; el aviso solo aparece para grandes eliminaciones. Cuando intentaba eliminar un par de cosas y aparece el mensaje, se sorprende y se da cuenta de que accidentalmente escribió "foo *".
Nick Matteo
@Kundor Eliminar más de tres archivos y eliminar de forma recursiva (la confirmación está deshabilitada por el habitual -rfque acabo de descubrir) son proxys pobres para detectar un posible error. No es probable que desee eliminar un subdirectorio. El mensaje no ayuda porque solo confirma lo que el usuario dijo que hiciera sin agregar información útil en un momento en que el usuario no está buscando verificar. "rm: ¿eliminar 1 argumento recursivamente?" "Sí, elimine el directorio, ¡acabo de decirle que haga eso! ... espere, ¿qué directorio fue ese? ¡¡MIERDA !!!"
Schwern
2

Enseño a todos sobre el !$= último argumento en el último truco del comando:

% ls job[XYZ].*
jobX.out1
jobX.out2
[rest of the matches]

% rm !$

Esto permite una inspección de la expansión de comodines, y luego usar el mismo patrón de globo sin la posibilidad de insertar un espacio antes del *.

También sugiero que la gente nunca corte y pegue un patrón comodín en una línea de comando potencialmente destructiva. Porque en mis propias manos eso ha sido un problema :)

Un técnico en mi laboratorio cometió este error la semana pasada (3 meses de trabajo), y sí, tuvimos una copia de seguridad (1 día de retraso).

kael
fuente
0

Todo el mundo parece decir: "Ten más cuidado", "No hagas un alias / confirmación porque te habrás acostumbrado a no prestarle la debida atención".

Genial, y todo. Quiero decir, no creo que debas hacer un alias para rm(ni rmrf, ya que podrías arruinarlo fácilmente y escribir el comando real).

Pero, ¿por qué no puede crear un alias / script y llamarlo, decirlo removey solo alimentarlo con un argumento (por ejemplo, $ 1)? El comodín debería ser de $ 2, debido al espacio inadvertido (¿amiright?) Y, por lo tanto, su script / wrapper / alias no se alimentará con el segundo. Sí, solo puede hacer un conjunto de eliminaciones (con un comodín) a la vez, pero ese es el precio que pagaría.

Si estuviera escribiendo algo bueno, podría hacer que me diga la cantidad de archivos y directorios que planea eliminar, y el tamaño total de las cosas que estaba eliminando, y luego pedir una confirmación, pero eso podría impedir su flujo. ¿Quizás hacer de eso una opción de bandera remove? (-yo). También es posible que desee hacer un cheque de $ 1 para ver si es solo un comodín y solicitar una confirmación, y enumerar en qué directorio se encuentra realmente.


Por otro lado, hay una serie de rmreemplazos por ahí. Muchos están tratando de cumplir con la papelera de escritorio de la interfaz de usuario. Puede que valga la pena analizar algunos de ellos.

usuario3082
fuente
66
Su alias "eliminar" nunca eliminará más de un archivo a la vez. No puede usar un comodín, porque el shell lo expande antes de que el comando lo vea.
hymie
Entonces, ¿evaluarlo y luego incluirlo en el script?
user3082
¿Entonces quieres escribir remove \*? Si su script permite que el shell expanda su entrada globalmente, no veo que ayude mucho.
Peter Cordes
0

Un truco muy simple es poner -rfal final: rm whatever* -rf
esto reduce drásticamente la tasa de error, porque escribe más caracteres después del *, por lo que tiene más tiempo para ver errores tipográficos.
Esto no resuelve todo. Solo un simple truco diario.

Gregory MOUSSAT
fuente