Buat `rm` pindah ke tempat sampah

54

Apakah ada skrip / aplikasi Linux yang, alih-alih menghapus file, memindahkannya ke lokasi “tempat sampah” khusus? Saya ingin ini sebagai pengganti rm(bahkan mungkin aliasing yang terakhir; ada pro dan kontra untuk itu).

Yang dimaksud dengan "sampah" adalah folder khusus. Satu mv $* ~/.trashadalah langkah pertama, tetapi idealnya ini juga harus menangani membuang beberapa file dengan nama yang sama tanpa menimpa file sampah yang lama, dan memungkinkan untuk mengembalikan file ke lokasi asli mereka dengan perintah sederhana (semacam "undo"). Selain itu, alangkah baiknya jika sampah secara otomatis dikosongkan saat reboot (atau mekanisme serupa untuk mencegah pertumbuhan tanpa akhir).

Ada solusi parsial untuk ini, tetapi tindakan "mengembalikan" tidak sepele. Apakah ada solusi yang ada untuk ini yang tidak bergantung pada sistem sampah dari shell grafis?

(Sebagai tambahan, telah ada diskusi tanpa akhir apakah pendekatan ini dibenarkan, daripada menggunakan cadangan sering dan VCS. Sementara diskusi itu ada benarnya, saya percaya masih ada ceruk untuk permintaan saya.)

Konrad Rudolph
sumber
4
Ini mungkin terkait dengan pertanyaan SuperUser Dua perintah untuk memindahkan file ke sampah. Apa bedanya? . Saya telah menggunakan gvfs-trashdi masa lalu, tetapi tidak pernah perlu untuk memulihkan dari baris perintah sampai Anda memicu rasa ingin tahu saya. Jawaban untuk pertanyaan terkait mungkin bisa membantu.
ephsmith
1
@ fsmith Terima kasih, tautan yang bagus. Masalah dengan pendekatan tersebut adalah bahwa mereka terikat pada shell desktop spesifik (apa istilah yang benar di sini?) Implementasi, sesuatu yang ingin saya hindari.
Konrad Rudolph
1
Apakah memindahkan file dari sistem file apa saja ke ~ Anda disengaja? Karena suatu hari Anda mungkin menghapus gambar iso 4GB yang berada di dir yang dipasang dengan sshfs dari server yang sangat jauh.
Mischa Arefiev
1
@Mischa Sejujurnya, saya tidak terlalu memikirkannya. Yang mengatakan, itu harus bekerja dengan hak-hak pengguna biasa, sehingga target harus menjadi lokasi yang dapat ditulisi dan seharusnya tidak memerlukan terlalu banyak konfigurasi.
Konrad Rudolph
3
Lakukan apa pun yang Anda inginkan seperti solusi yang dijabarkan dalam jawaban di bawah, tetapi jangan beri nama rm. Seperti yang ditunjukkan oleh orang lain, penggantian nama / repurposing perintah standar membuat Anda rentan ketika Anda terbiasa menggunakannya di sistem lain, tetapi itu juga akan menyebabkan masalah bagi orang lain (mungkin membantu Anda) menggunakan sistem / akun Anda ketika hasil yang tidak terduga terjadi.
Joe

Jawaban:

37

Ada spesifikasi (konsep) untuk Sampah di freedesktop.org. Ini tampaknya apa yang biasanya diterapkan oleh lingkungan desktop.

Implementasi commandline adalah trash-cli . Tanpa melihat lebih dekat, tampaknya memberikan kesungguhan yang Anda inginkan. Jika tidak, beri tahu kami sejauh mana ini hanya solusi sebagian.

Sejauh menggunakan program apa pun sebagai pengganti / alias untuk rmyang bersangkutan, ada alasan bagus untuk tidak melakukannya. Yang paling penting bagi saya adalah:

  • Program perlu memahami / menangani semua rmopsi dan bertindak sesuai
  • Ini memiliki risiko terbiasa dengan semantik "rm baru" Anda dan melakukan perintah dengan konsekuensi fatal ketika bekerja pada sistem orang lain
zpea
sumber
Ada juga libtrash yang memindahkan semua file yang dihapus secara otomatis ke tempat sampah melalui LD_PRELOAD (tetapi tampaknya memiliki beberapa bug). Autotrash membantu membersihkan sampah dengan mudah.
jofel
Saya ingin tahu tentang mendapatkan kebiasaan menggunakan rm. Sayangnya, saya sudah terbiasa.
Konrad Rudolph
@jofel: libtrash memiliki konsep yang sangat bagus. Beberapa lapisan lebih dalam dari pendekatan lainnya. Sayang sekali itu buggy (dan sepertinya tidak terlalu aktif).
zpea
4
@KonradRudolph: Maksud saya, orang terbiasa dengan kenyataan bahwa rm (yang diganti) tidak benar-benar menghapus apa pun, sehingga orang kurang berhati-hati, karena pemulihan selalu dimungkinkan. Tentu saja, menggunakan rm itu sendiri bukanlah hal yang buruk, juga tidak terbiasa.
zpea
4
Saya akhirnya menggunakan solusi ini, dan menonaktifkan rmjadi saya tidak bisa menggunakannya secara tidak sengaja (masih ada /bin/rmkalau-kalau saya benar-benar membutuhkannya).
Konrad Rudolph
9

Trash-cli adalah aplikasi linux yang dapat diinstal menggunakan apt-get di Ubuntu atau yum di Fedora. Menggunakan perintah trash listOfFilesakan memindahkan yang ditentukan ke tempat sampah Anda.

namu
sumber
Untuk mendukung saran ini: apple.stackexchange.com/a/17637/37190
Ioannis Filippidis
7

Jawaban sebelumnya menyebutkan perintah trash-clidan rmtrash. Tidak satupun dari mereka ditemukan secara default di Ubuntu 18.04, tetapi perintahnya gioadalah. gio help trashOutput memerintah :

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

Move files or directories to the trash.

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

Saya diuji menggunakan gio trash FILENAMEpada baris perintah, dan itu berfungsi seperti saya telah memilih file di browser file dan mengklik tombol DEL: file dipindahkan ke folder Trash desktop. (Perintah tidak meminta konfirmasi walaupun saya tidak menggunakan -fopsi.)

Menghapus file dengan cara ini adalah reversibel, sementara menjadi lebih mudah daripada mendefinisikan ulang rmmenjadi rm -iuntuk keselamatan dan harus mengkonfirmasi setiap penghapusan, yang masih menyisakan Anda beruntung jika Anda secara tidak sengaja mengkonfirmasi penghapusan Anda tidak harus memiliki.

Saya menambahkan alias tt='gio trash'ke file definisi alias saya; ttadalah mnemonic untuk To Trash.

Ditambahkan pada edit pada 2018-06-27: Pada mesin server, tidak ada yang setara dengan direktori tempat sampah. Saya telah menulis skrip Bash berikut yang melakukan pekerjaan; pada mesin desktop, ia menggunakan gio trash, dan pada mesin lain, memindahkan file yang diberikan sebagai parameter ke direktori tempat sampah yang dibuatnya. Script diperbarui pada 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
sumber
5

Ada sedikit utilitas yang disebut rmtrash yang melakukan ini.

Tampaknya tidak menanggapi params seperti -ratau -f(tampaknya pada dasarnya hanya memindahkan file / direktori ke direktori ~ / .Trash), tetapi tidak akan menimpa file dengan nama yang sama (itu menambahkan "Salin" ke seperti-bernama file / direktori).

Untuk menginstal dengan minuman

brew install rmtrash
alias rm='rmtrash' >> ~/.bashrc
FreePender
sumber
github.com/nateshmbhat/rm-trash . "rm-trash", menangani juga nama file duplikat dan penghapusan rekursif. Saksikan berikut ini.
Natesh bhat
4

Berikut ini adalah sistem sampah cepat dan kotor yang mengatasi bentrokan nama dan bahkan memungkinkan banyak file yang dihapus di jalur yang sama selama Anda tidak menghapus lebih dari satu file per detik.

Peringatan: Saya mengetik kode ini langsung ke browser saya. Mungkin rusak. Jangan menggunakannya pada data produksi.

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
)

Masalah Dikenal:

  • Tidak mengatasi dengan anggun jika Anda mencoba menghapus file yang sama beberapa kali secara bersamaan.
  • Direktori tempat sampah mungkin menjadi sangat besar, file-file tersebut harus dikirim ke subdirektori berdasarkan beberapa digit pertama dari hash.
  • trashharus mengatasi baris baru dalam nama file, tetapi untrashtidak karena itu bergantung pada grepdan baris baru tidak lolos dalam file metadata.
Gilles 'SANGAT berhenti menjadi jahat'
sumber
2

Mulailah dengan mendefinisikan move_to_trashfungsi:

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

Kemudian alias rmuntuk itu:

alias rm='move_to_trash'

Anda selalu dapat menghubungi tua rmdengan melarikan diri dengan garis miring terbalik, seperti ini: \rm.

Saya tidak tahu bagaimana cara membuat direktori tempat sampah kosong saat reboot (tergantung pada sistem Anda, Anda mungkin harus melihat ke dalam rc*skrip), tetapi bisa juga bermanfaat untuk membuat crontugas yang mengosongkan direktori secara berkala.

rahmu
sumber
2
Sayangnya, itu adalah bagian yang mudah ...: /
Konrad Rudolph
Skrip ini juga dapat membuat file teks dalam direktori tersembunyi untuk setiap file yang berisi direktori tempat ia berada. Skrip pemulihan dapat membaca lokasi lama dan memindahkannya kembali.
ephsmith
Ini juga memiliki bahaya beberapa file yang dihapus dengan nama yang sama akan bertabrakan di direktori tempat sampah, dan hanya yang terakhir "dihapus" akan bertahan untuk dapat dipulihkan.
killermist
@killermist, ya. Tentu saja orang perlu melakukan sesuatu tambahan dengan perintah bergerak. Beri nama file "trashed" apa pun yang Anda inginkan dan pertahankan jalur aslinya: | Ini semua berteriak "mengapa menciptakan kembali roda". Ada solusi yang ada untuk masalah ini.
ephsmith
Juga, gunakan nama alias yang berbeda. Bekerja di komputer lain tanpa alias Anda, satu panggilan ke rmsana dan pergi file Anda. delmungkin pilihan yang lebih baik.
glenn jackman
1

Anda dapat menggunakan del saya:

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

del memindahkan file dalam .del / subdirektori (dan kembali)

penggunaan: del [-v] [-u] file
       del [-v] -p [-r] [-d hari] [direktori]
       del [-v] -l
Pilihan: -v mode verbose
         -u batalkan penghapusan file
         -p membersihkan file yang dihapus [lebih tua dari -d hari]
         -r rekursif (semua subdirektori)
         -l daftar file yang dihapus
contoh: del * .tmp # hapus semua file * .tmp
          del -u project.pl # undelete project.pl
          del -vprd 2 # verbose purge file yang dihapus lebih dari 2 hari
Framstag
sumber
0

Di KDE 4.14.8 saya menggunakan perintah berikut untuk memindahkan file ke tempat sampah (seolah-olah itu dihapus di Dolphin):

kioclient move path_to_file_or_directory_to_be_removed trash:/

Lampiran I: Saya menemukan tentang perintah dengan

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

Lampiran II: fungsi (lalu sumberkan di .bashrc Anda)

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
}
pengguna3804598
sumber