Hacer que 'rm' se mueva a la basura

54

¿Existe un script / aplicación de Linux que, en lugar de eliminar archivos, los mueva a una ubicación especial de "papelera"? Me gustaría esto como un reemplazo para rm(tal vez incluso alias el último; hay pros y contras para eso).

Por "basura" me refiero a una carpeta especial. Un solo mv $* ~/.trashpaso es el primer paso, pero idealmente esto también debería manejar la eliminación de varios archivos del mismo nombre sin sobrescribir los archivos desechados más antiguos y permitir restaurar los archivos a su ubicación original con un comando simple (una especie de "deshacer"). Además, sería bueno que la basura se vacíe automáticamente al reiniciar (o un mecanismo similar para evitar un crecimiento sin fin).

Existen soluciones parciales para esto, pero la acción de "restauración" en particular no es trivial. ¿Existen soluciones existentes para esto que no se basan en un sistema de basura desde un shell gráfico?

(Como comentario aparte, ha habido discusiones interminables sobre si este enfoque está justificado, en lugar de usar copias de seguridad frecuentes y VCS. Si bien esas discusiones tienen un punto, creo que todavía hay un nicho para mi solicitud).

Konrad Rudolph
fuente
44
Esto puede estar relacionado con la pregunta SuperUser Dos comandos para mover archivos a la papelera. ¿Cual es la diferencia? . Lo he usado gvfs-trashen el pasado, pero nunca tuve la necesidad de restaurar desde la línea de comandos hasta que despertó mi curiosidad. La respuesta a la pregunta vinculada puede ser de ayuda.
ephsmith
1
@ephsmith Gracias, buen enlace. Sin embargo, el problema con esos enfoques es que están vinculados a implementaciones específicas de shell de escritorio (¿cuál es el término correcto aquí?), Algo que quiero evitar.
Konrad Rudolph
1
¿Mover archivos de cualquier sistema de archivos a su ~ intencional? Porque algún día podría estar eliminando una imagen iso de 4GB que reside en un directorio montado con sshfs desde un servidor realmente remoto.
Mischa Arefiev
1
@Mischa Para ser honesto, no pensé mucho en eso. Dicho esto, debería funcionar con los derechos de usuario habituales, por lo que el objetivo debe ser una ubicación que se pueda escribir y que no requiera demasiada configuración.
Konrad Rudolph
3
Haga lo que quiera, como las soluciones descritas en las respuestas a continuación, pero no lo llame rm. Como lo señalaron otros, renombrar / reutilizar los comandos estándar lo deja vulnerable cuando intenta usarlos habitualmente en otros sistemas, pero también causará problemas para que cualquier otra persona (tal vez lo ayude) use su sistema / cuenta cuando ocurran resultados inesperados.
Joe

Respuestas:

37

Hay una especificación (borrador) para la Papelera en freedesktop.org. Aparentemente es lo que generalmente implementan los entornos de escritorio.

Una implementación de línea de comandos sería trash-cli . Sin haber visto más de cerca, parece proporcionar la funcionalidad que desea. Si no, díganos hasta qué punto esto es solo una solución parcial.

En lo que respecta al uso de cualquier programa como reemplazo / alias rm, existen buenas razones para no hacerlo. Lo más importante para mí son:

  • El programa necesitaría comprender / manejar todas rmlas opciones y actuar en consecuencia
  • Tiene el riesgo de acostumbrarse a la semántica de su "nueva empresa" y ejecutar comandos con consecuencias fatales cuando trabaja en los sistemas de otras personas
zpea
fuente
También hay libtrash que mueve todos los archivos eliminados automáticamente a la papelera a través de LD_PRELOAD (pero parece tener varios errores). Autotrash ayuda a limpiar la basura de una manera fácil.
jofel
Me pregunto acerca de adquirir el hábito de usar rm. Ya estoy acostumbrado, desafortunadamente.
Konrad Rudolph
@jofel: libtrash tiene un concepto muy bueno. Algunas capas más profundas que los otros enfoques. Es una pena que tenga errores (y no parece muy activo).
zpea
44
@KonradRudolph: Quise decir que uno se acostumbra al hecho de que rm (el reemplazado) realmente no elimina nada, por lo que uno es menos cuidadoso, ya que siempre es posible una restauración. Por supuesto, usar rm en sí mismo no es algo malo, ni tampoco acostumbrarse.
zpea
44
Terminé usando esta solución y deshabilitándola rmpara no poder usarla accidentalmente (todavía hay /bin/rmen caso de que realmente la necesite).
Konrad Rudolph el
9

Trash-cli es una aplicación de Linux que se puede instalar usando apt-get en Ubuntu o yum en Fedora. El uso del comando trash listOfFilesmoverá lo especificado a su papelera.

namu
fuente
En apoyo de esta sugerencia: apple.stackexchange.com/a/17637/37190
Ioannis Filippidis
7

Las respuestas anteriores mencionan comandos trash-cliy rmtrash. Ninguno de esos se encuentra por defecto en Ubuntu 18.04, pero el comando gioes. gio help trashSalidas dominantes :

Usage:
  gio trash [OPTION…] [LOCATION...]

Move files or directories to the trash.

Options:
  -f, --force     Ignore nonexistent files, never prompt
  --empty         Empty the trash

Lo probé usando gio trash FILENAMEen la línea de comando, y funciona igual que seleccioné el archivo en el explorador de archivos e hice clic en el botón DEL: el archivo se mueve a la carpeta Papelera del escritorio. (El comando no solicita confirmación aunque no utilicé la -fopción).

La eliminación de archivos de esta manera es reversible, mientras que ser más conveniente que la redefinición de rmser rm -ipara la seguridad y tener que confirmar cada eliminación, que todavía le deja fuera de suerte si se confirma accidentalmente una deleción que no debería tener.

Agregué alias tt='gio trash'a mi archivo de definiciones de alias; ttes un mnemotécnico para To Trash.

Agregado en edición el 27-06-2018: en las máquinas del servidor, no hay equivalente de un directorio de basura. He escrito el siguiente script de Bash que hace el trabajo; en máquinas de escritorio, usa gio trash, y en otras máquinas, mueve los archivos dados como parámetro (s) a un directorio de basura que crea. Guión actualizado el 2019-09-05.

#!/bin/bash
#
# move-to-trash
#
# Teemu Leisti 2019-09-05
#
# This script moves the files given as arguments to the trash directory, if they
# are not already there. It works both on (Gnome) desktop and server hosts.
#
# The script is intended as a command-line equivalent of deleting a file from a
# graphical file manager, which, in the usual case, moves the deleted file(s) to
# a built-in trash directory. On server hosts, the analogy is not perfect, as
# the script does not offer the functionality of restoring a trashed file to its
# original location, nor that of emptying the trash directory; rather, it offers
# an alternative to the 'rm' command, giving the user the peace of mind that
# they can still undo an unintended deletion before emptying the trash
# directory.
#
# To determine whether it's running on a desktop host, the script tests for the
# existence of the gio utility and of directory ~/.local/share/Trash. In case
# both exist, the script relies on the 'gio trash' command. Otherwise, it treats
# the host as a server.
#
# There is no built-in trash directory on server hosts, so the first invocation
# of the script creates directory ~/.Trash/, unless it already exists.
#
# The script appends a millisecond-resolution time stamp to all the files it
# moves to the trash directory, both to inform the user of the time of the
# deletion, and to avoid overwrites when moving a file to trash.
#
# The script will not choke on a nonexistent file. It outputs the final
# disposition of each argument: does not exist, was already in trash, or was
# moved to trash.


gio_command_exists=0
command -v gio > /dev/null 2>&1
if (( $? == 0 )) ; then
    gio_command_exists=1
fi

# Exit on using an uninitialized variable, and on a command returning an error.
# (The latter setting necessitates appending " || true" to those arithmetic
# calculations and other commands that can return 0, lest the shell interpret
# the result as signalling an error.)
set -eu

is_desktop=0

if [[ -d ~/.local/share/Trash ]] && (( gio_command_exists == 1 )) ; then
    is_desktop=1
    trash_dir_abspath=$(realpath ~/.local/share/Trash)
else
    trash_dir_abspath=$(realpath ~/.Trash)
    if [[ -e $trash_dir_abspath ]] ; then
        if [[ ! -d $trash_dir_abspath ]] ; then
            echo "The file $trash_dir_abspath exists, but is not a directory. Exiting."
            exit 1
        fi
    else
        mkdir $trash_dir_abspath
        echo "Created directory $trash_dir_abspath"
    fi
fi

for file in "$@" ; do
    file_abspath=$(realpath -- "$file")
    file_basename=$(basename -- "$file_abspath")
    if [[ ! -e $file_abspath ]] ; then
        echo "does not exist:   $file_abspath"
    elif [[ "$file_abspath" == "$trash_dir_abspath"* ]] ; then
        echo "already in trash: $file_abspath"
    else
        if (( is_desktop == 1 )) ; then
            gio trash "$file_abspath" || true
        else
            # The name of the moved file shall be the original name plus a
            # millisecond-resolution timestamp.
            move_to_abspath="$trash_dir_abspath/$file_basename-$(date '+%Y-%m-%d-at-%H-%M-%S.%3N')"
            while [[ -e "$move_to_abspath" ]] ; do
                # Generate a new name with a new timestamp, as the previously
                # generated one denoted an existing file.
                move_to_abspath="$trash_dir_abspath/$file_basename-$(date '+%Y-%m-%d-at-%H-%M-%S.%3N')"
            done
            # We're now almost certain that the file denoted by name
            # $move_to_abspath does not exist, as for that to be the case, an
            # extremely unlikely run condition would have had to take place:
            # some other process would have had to create a file with the name
            # $move_to_abspath after the execution of the existence test above.
            # However, to make absolute sure that moving the file to the trash
            # directory will always be successful, we shall give the '-f'
            # (force) flag to the 'mv' command.
            /bin/mv -f "$file_abspath" "$move_to_abspath"
        fi
        echo "moved to trash:   $file_abspath"
    fi
done
Teemu Leisti
fuente
5

Hay una pequeña utilidad llamada rmtrash que hace esto.

No parece responder a parámetros como -ro -f(parece que esencialmente solo está moviendo el archivo / directorio al directorio ~ / .Trash), pero no anulará los archivos con el mismo nombre (agrega "Copiar" a archivos / directorios con el mismo nombre).

Para instalar con cerveza

brew install rmtrash
alias rm='rmtrash' >> ~/.bashrc
FreePender
fuente
github.com/nateshmbhat/rm-trash . "rm-trash", también maneja nombres de archivos duplicados y eliminaciones recursivas. Echale un vistazo.
Natesh bhat
4

Aquí hay un sistema de basura rápido y sucio que hace frente a los conflictos de nombres e incluso permite múltiples archivos eliminados en la misma ruta siempre que no elimine más de un archivo por segundo.

Advertencia: escribí este código directamente en mi navegador. Probablemente esté roto. No lo use en datos de producción.

trash_root=~/.trash
mkdir "$trash_root"
newline='
'
trash () (
  time=$(date +%Y%m%d%H%M%S)
  for path; do
    case $path in /*) :;; *) path=$PWD/$path;; esac
    mkdir "$trash_root${path%/*}"
    case ${path##*/} in
      ?*.*) ext="${path##*.}"; ext="${ext##*$newline}";;
      *) ext="";;
    esac
    metadata="Data: $hash.$ext
Date: $time
Path: $path
"
    hash=$(printf %s "$metadata" | sha1sum)
    printf %s "$metadata" "$trash_root/$hash-$time-metadata"
    mv "$path" "$trash_root/$hash.$ext"
  done
)

untrash () (
  IFS='
  '
  root=$PWD
  cd "$trash_root" || return 2
  err=0
  for path; do
    if [ -e "$path" ]; then
      echo 1>&2 "Not even attempting to untrash $path over an existing file"
      if [ $err -gt 2 ]; then err=2; fi
      continue
    fi
    case $path in /*) :;; *) path=$root/$path;; esac 
    if metadata=$(grep -l -F -x "Path: $path" *-metadata |
                  sort -t - -k 2 | tail -n 1); then
      mv "${metadata%%-*}".* "$path"
    else
      echo 1>&2 "$path: no such deleted file"
      if [ $err -gt 1 ]; then err=1; fi
    fi
  done
  return $err
)

Problemas conocidos:

  • No funciona correctamente si intenta eliminar el mismo archivo varias veces al mismo tiempo.
  • El directorio de la papelera puede volverse enorme, los archivos deben enviarse a subdirectorios basados ​​en los primeros dígitos del hash.
  • trashdebería hacer frente a las nuevas líneas en los nombres de archivo, pero untrashno lo hace porque se basa grepy las nuevas líneas no se escapan en el archivo de metadatos.
Gilles 'SO- deja de ser malvado'
fuente
2

Comience definiendo una move_to_trashfunción:

move_to_trash () {
    mv "$@" ~/.trash
}

Entonces alias rma eso:

alias rm='move_to_trash'

Siempre se puede llamar de edad rmal escapar con una barra invertida, como esto: \rm.

No sé cómo vaciar el directorio de la papelera al reiniciar (dependiendo de su sistema, es posible que tenga que buscar en los rc*scripts), pero también podría valer la pena crear una crontarea que vacíe el directorio periódicamente.

rahmu
fuente
2
Desafortunadamente, esa fue la parte fácil ...: /
Konrad Rudolph
Este script también podría crear un archivo de texto en un directorio oculto para cada archivo que contiene el directorio en el que se encontraba. Un script de restauración podría leer la ubicación anterior y moverla de regreso.
ephsmith
Esto también tiene el riesgo de que múltiples archivos eliminados con el mismo nombre colisionen en el directorio de la papelera, y solo el último "eliminado" sobreviviría para poder ser recuperado.
killermist
@killermist, sí. Por supuesto, uno tendría que hacer algo adicional con el comando mover. Asigne un nombre al archivo "desechado" como desee y mantenga la ruta original: | Todo esto grita "por qué recrear la rueda". Existen soluciones existentes para este problema.
ephsmith
Además, use un nombre de alias diferente. Trabaja en otra máquina sin tus alias, una llamada rmy ahí van tus archivos. delPodría ser una mejor opción.
Glenn Jackman
1

Puedes usar mi del:

http://fex.belwue.de/fstools/del.html

del mueve archivos en un subdirectorio .del / (y viceversa)

uso: del [-v] [-u] archivo (s)
       del [-v] -p [-r] [-d días] [directorio]
       del [-v] -l
opciones: -v modo detallado
         -u recuperar archivos
         -p purgar archivos eliminados [anterior a -d días]
         -r recursivo (todos los subdirectorios)
         -l listar archivos borrados
ejemplos: del * .tmp # eliminar todos los archivos * .tmp
          del -u project.pl # undelete project.pl
          del -vprd 2 # verbose purge borró archivos anteriores a 2 días
Framstag
fuente
0

En KDE 4.14.8 utilicé el siguiente comando para mover archivos a la papelera (como si se hubiera eliminado en Dolphin):

kioclient move path_to_file_or_directory_to_be_removed trash:/

Apéndice I: encontré sobre el comando con

    ktrash --help
...
    Note: to move files to the trash, do not use ktrash, but "kioclient move 'url' trash:/"

Apéndice II: la función (luego fuente en su .bashrc)

function Rm {
    if [[ "$1" == '--help' ]] ; then
        echo 'USAGE:'
        echo 'Rm --help # - show help'
        echo 'Rm file1 file2 file3 ...'
        echo 'Works for files and directories'
        return
    fi
    for i in "$@" ;
    do
        kioclient move $i trash:/ && echo "$i was trashed"
    done
}
usuario3804598
fuente