Fai muovere `rm` nel cestino


54

Esiste uno script / un'applicazione Linux che, invece di eliminare i file, li sposta in una posizione "cestino" speciale? Vorrei questo come sostituto di rm(forse anche alias di quest'ultimo; ci sono pro e contro per quello).

Per "cestino" intendo una cartella speciale. Un singolo mv $* ~/.trashè un primo passo, ma idealmente questo dovrebbe anche gestire il cestino di diversi file con lo stesso nome senza sovrascrivere i vecchi file nel cestino e consentire di ripristinare i file nella loro posizione originale con un semplice comando (una sorta di "annulla"). Inoltre, sarebbe bello se il cestino fosse automaticamente svuotato al riavvio (o un meccanismo simile per impedire una crescita infinita).

Esistono soluzioni parziali per questo, ma in particolare l'azione di "ripristino" non è banale. Ci sono soluzioni esistenti per questo che non si basano su un sistema di spazzatura da una shell grafica?

(A parte, ci sono state infinite discussioni sulla giustificazione di questo approccio, piuttosto che sull'uso frequente di backup e VCS. Mentre quelle discussioni hanno un punto, credo che ci sia ancora una nicchia per la mia richiesta.)


4
Ciò può essere correlato alla domanda di SuperUser Due comandi per spostare i file nel cestino. Qual è la differenza? . Ho usato gvfs-trashin passato, ma non ho mai avuto bisogno di ripristinare dalla riga di comando fino a quando non hai suscitato la mia curiosità. La risposta alla domanda collegata può essere di aiuto.
ephsmith il

1
@smsmith Grazie, buon collegamento. Il problema con questi approcci è che sono legati a specifiche implementazioni della shell desktop (qual è il termine corretto qui?), Cosa che voglio evitare.
Konrad Rudolph,

1
Lo spostamento di file da qualsiasi file system sul tuo ~ è intenzionale? Perché un giorno potresti cancellare un'immagine iso da 4 GB che risiede su una directory montata con sshfs da un server veramente remoto.
Mischa Arefiev,

1
@Mischa Ad essere sincero, non ci ho pensato molto. Detto questo, dovrebbe funzionare con i soliti diritti dell'utente, quindi la destinazione deve essere una posizione che sia scrivibile e non dovrebbe richiedere troppa configurazione.
Konrad Rudolph,

3
Fai quello che vuoi come le soluzioni descritte nelle risposte seguenti, ma non chiamarlo rm. Come sottolineato da altri, rinominare / riutilizzare i comandi standard ti rende vulnerabile quando provi abitualmente a usarli su altri sistemi, ma causerà anche problemi a chiunque (forse ti assisterà) utilizzando il tuo sistema / account quando si verificano risultati imprevisti.
Joe,

Risposte:


37

C'è una specifica (bozza) per Cestino su freedesktop.org. Apparentemente è ciò che viene solitamente implementato dagli ambienti desktop.

Un'implementazione da riga di comando sarebbe trash-cli . Senza aver guardato più da vicino, sembra fornire la funzionalità che desideri. In caso contrario, comunicaci in che misura questa è solo una soluzione parziale.

Per quanto riguarda l'utilizzo di qualsiasi programma come sostituto / alias rm, ci sono buone ragioni per non farlo. I più importanti per me sono:

  • Il programma dovrebbe comprendere / gestire tutte rmle opzioni e agire di conseguenza
  • Ha il rischio di abituarsi alla semantica del "nuovo rm" e di eseguire comandi con conseguenze fatali quando si lavora su sistemi di altre persone

C'è anche libtrash che sposta automaticamente tutti i file eliminati nel cestino tramite LD_PRELOAD (ma sembra avere diversi bug). L'autotrash aiuta a pulire la spazzatura in modo semplice.
jofel l'

Mi chiedo cosa sia prendere l'abitudine di usare rm. Purtroppo ho già l'abitudine.
Konrad Rudolph,

@jofel: libtrash ha un concetto davvero carino. Alcuni strati più profondi degli altri approcci. È un peccato che sia difettoso (e non sembra molto attivo).
zpea,

4
@KonradRudolph: Volevo dire che ci si abitua al fatto che rm (quello sostituito) non cancella davvero nulla, quindi si è meno attenti, poiché è sempre possibile un ripristino. Naturalmente, usare rm stesso non è una cosa negativa, né ci si sta abituando.
zpea,

4
Ho finito con l'uso di questa soluzione e la disabilitazione, rmquindi non posso usarla accidentalmente (c'è ancora /bin/rmnel caso in cui ne abbia davvero bisogno).
Konrad Rudolph,


7

Le risposte precedenti menzionano comandi trash-clie rmtrash. Nessuno di questi si trova di default su Ubuntu 18.04, ma il comando gioè. gio help trashUscite comandanti :

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

Move files or directories to the trash.

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

Ho provato usando gio trash FILENAMEdalla riga di comando e funziona proprio come se avessi selezionato il file nel browser dei file e fatto clic sul pulsante DEL: il file viene spostato nella cartella Cestino del desktop. (Il comando non richiede la conferma anche se non ho usato l' -fopzione.)

L'eliminazione di file in questo modo è reversibile, pur essendo più conveniente di ridefinire rmdi essere rm -iper la sicurezza e di dover confermare ogni eliminazione, che si lascia ancora fuori di fortuna se si conferma accidentalmente una cancellazione non si dovrebbe avere.

Ho aggiunto alias tt='gio trash'al mio file delle definizioni alias; ttè un mnemonico per To Trash.

Aggiunto alla modifica il 27/06/2018: sui computer server non esiste un equivalente di una directory cestino. Ho scritto il seguente script Bash che fa il lavoro; su macchine desktop, utilizza gio trashe su altre macchine, sposta i file dati come parametri in una directory cestino che crea. Script aggiornato il 05-09-2019.

#!/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

5

C'è una piccola utility chiamata rmtrash che lo fa.

Non sembra rispondere a parametri come -ro -f(sembra essenzialmente spostare il file / directory nella directory ~ / .Trash), ma non sovrascriverà i file con lo stesso nome (aggiunge "Copia" a file / directory con nomi simili).

Da installare con brew

brew install rmtrash
alias rm='rmtrash' >> ~/.bashrc

github.com/nateshmbhat/rm-trash . "rm-trash", gestisce anche nomi di file duplicati ed eliminazioni ricorsive. Controlla.
Natesh bhat il

4

Ecco un sistema di cestino rapido e sporco che affronta gli scontri con i nomi e consente persino più file eliminati sullo stesso percorso purché non si elimini più di un file al secondo.

Attenzione: ho digitato questo codice direttamente nel mio browser. Probabilmente è rotto. Non utilizzarlo sui dati di produzione.

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
)

Problemi noti:

  • Non risolve il problema se si tenta di eliminare lo stesso file più volte contemporaneamente.
  • La directory cestino può diventare enorme, i file dovrebbero essere inviati in sottodirectory basate sulle prime cifre dell'hash.
  • trashdovrebbe far fronte alle newline nei nomi dei file, ma untrashnon perché si basa su grepe le newline non sono salvate nel file dei metadati.

2

Inizia definendo una move_to_trashfunzione:

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

Quindi alias rma quello:

alias rm='move_to_trash'

È sempre possibile chiamare vecchio rmfuggendo con un backslash, come questo: \rm.

Non so come rendere vuota la directory cestino al riavvio (a seconda del sistema in uso, potrebbe essere necessario esaminare gli rc*script), ma potrebbe anche valere la pena creare cronun'attività che svuota periodicamente la directory.


2
Sfortunatamente, quella era la parte facile ...: /
Konrad Rudolph il

Questo script potrebbe anche creare un file di testo in una directory nascosta per ogni file che contiene la directory in cui si trovava. Uno script di ripristino potrebbe leggere la vecchia posizione e spostarla indietro.
ephsmith il

Ciò comporta anche il rischio che più file eliminati con lo stesso nome si scontrino nella directory cestino e solo l'ultimo "eliminato" sopravviverebbe per poter essere recuperato.
assassino

@killermist, sì. Ovviamente si dovrebbe fare qualcosa in più con il comando move. Denominare il file "cestinato" come desiderato e mantenere il percorso originale: | Tutto questo grida "perché ricreare la ruota". Esistono soluzioni esistenti a questo problema.
ephsmith l'

Inoltre, usa un nome alias diverso. Lavora su un altro computer senza i tuoi alias, una chiamata a rme lì vanno i tuoi file. delpotrebbe essere una scelta migliore.
Glenn Jackman,

1

Puoi usare il mio del:

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

del sposta i file in una sottodirectory .del / (e viceversa)

utilizzo: del [-v] [-u] file
       del [-v] -p [-r] [-d giorni] [directory]
       del [-v] -l
opzioni: -v modalità dettagliata
         -u ripristina file
         -p elimina i file eliminati [precedenti a -d giorni]
         -r ricorsivo (tutte le sottodirectory)
         -l elenca i file eliminati
esempi: del * .tmp # elimina tutti i file * .tmp
          del -u project.pl # undelete project.pl
          del -vprd 2 # verbose elimina i file eliminati più vecchi di 2 giorni

0

In KDE 4.14.8 ho usato il seguente comando per spostare i file nel cestino (come se fossero stati rimossi in Dolphin):

kioclient move path_to_file_or_directory_to_be_removed trash:/

Appendice I: ho scoperto il comando con

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

Appendice II: la funzione (quindi sorgente nel tuo .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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.