Niech „rm” przejdzie do kosza


54

Czy istnieje skrypt / aplikacja dla systemu Linux, która zamiast usuwać pliki, przenosi je do specjalnej lokalizacji „kosza”? Chciałbym to jako zamiennik rm(może nawet aliasy tego drugiego; są za i przeciw).

Przez „kosz” rozumiem specjalny folder. Pojedynczy mv $* ~/.trashto pierwszy krok, ale najlepiej powinien również obsługiwać usuwanie kilku plików o tej samej nazwie bez nadpisywania starszych plików w trybie kosza i umożliwiać przywracanie plików do ich pierwotnej lokalizacji za pomocą prostego polecenia (rodzaj „cofania”). Ponadto byłoby miło, gdyby kosz był automatycznie opróżniany podczas ponownego uruchamiania (lub podobny mechanizm zapobiegający niekończącemu się rozwojowi).

Istnieją częściowe rozwiązania tego problemu, ale działanie „przywracania” nie jest trywialne. Czy istnieją jakieś rozwiązania tego problemu, które nie opierają się na systemie kosza z graficznej powłoki?

(Nawiasem mówiąc, toczyły się niekończące się dyskusje, czy takie podejście jest uzasadnione, zamiast częstych kopii zapasowych i VCS. Chociaż te dyskusje mają rację, uważam, że dla mojej prośby jest jeszcze nisza).


4
Może to być związane z pytaniem SuperUser. Dwa polecenia do przeniesienia plików do kosza. Co za różnica? . Używałem gvfs-trashw przeszłości, ale nigdy nie musiałem przywracać z wiersza poleceń, dopóki nie wzbudzisz mojej ciekawości. Pomocna może być odpowiedź na powiązane pytanie.
efmith

1
@ephsmith Dzięki, dobry link. Problem z tymi podejściami polega na tym, że są one związane z konkretnymi implementacjami powłoki pulpitu (jaki jest tutaj właściwy termin?), Czego chcę uniknąć.
Konrad Rudolph,

1
Czy przenoszenie plików z dowolnego systemu plików do ~ jest zamierzone? Ponieważ pewnego dnia możesz usuwać obraz ISO 4 GB rezydujący w katalogu zamontowanym za pomocą sshfs z naprawdę zdalnego serwera.
Mischa Arefiev,

1
@Mischa Szczerze mówiąc, nie zastanawiałem się nad tym. To powiedziawszy, powinno działać ze zwykłymi prawami użytkownika, więc celem musi być lokalizacja do zapisu i nie wymagająca zbyt dużej konfiguracji.
Konrad Rudolph

3
Rób co chcesz, na przykład rozwiązania przedstawione w odpowiedziach poniżej, ale nie nazywaj tego rm. Jak zauważyli inni, zmiana nazwy / zmiany przeznaczenia standardowych poleceń pozostawia cię podatnym na zagrożenia, gdy zwykle próbujesz ich używać w innych systemach, ale także spowoduje problemy dla innych osób (być może pomagających) w używaniu twojego systemu / konta, gdy pojawią się nieoczekiwane wyniki.
Joe

Odpowiedzi:


37

Na stronie freedesktop.org znajduje się specyfikacja (wersja robocza) Kosza . Najwyraźniej jest to zwykle realizowane przez środowiska komputerowe.

Implementacją wiersza polecenia byłoby trash-cli . Bez dokładniejszego spojrzenia wydaje się on zapewniać pożądaną funkcjonalność. Jeśli nie, powiedz nam, jak dalece jest to tylko częściowe rozwiązanie.

Jeśli chodzi o używanie dowolnego programu jako zamiennika / aliasu rm, istnieją dobre powody, aby tego nie robić. Najważniejsze dla mnie są:

  • Program musiałby zrozumieć / obsługiwać wszystkie rmopcje i odpowiednio postępować
  • Grozi to przyzwyczajeniem się do semantyki „nowego rm” i wykonywaniem poleceń o fatalnych skutkach podczas pracy na systemach innych ludzi

Istnieje również libtrash, który automatycznie przenosi wszystkie usunięte pliki do kosza za pośrednictwem LD_PRELOAD (ale wydaje się, że zawiera kilka błędów). Autotrash pomaga w łatwy sposób wyczyścić śmieci.
jofel

Zastanawiam się nad tym, jak się przyzwyczaić. Niestety mam już nawyk.
Konrad Rudolph,

@jofel: libtrash ma naprawdę fajną koncepcję. Kilka warstw głębiej niż inne podejścia. Szkoda, że ​​jest wadliwy (i nie wydaje się bardzo aktywny).
zpea

4
@KonradRudolph: Miałem na myśli, że przyzwyczaiłem się do faktu, że rm (zastąpiony) tak naprawdę niczego nie usuwa, więc jest mniej ostrożny, ponieważ przywracanie jest zawsze możliwe. Oczywiście używanie samego rm nie jest złe, ani się do niego nie przyzwyczaja.
zpea,

4
Skończyło się na tym rozwiązaniu i wyłączeniu, rmwięc nie mogę go użyć przypadkowo (nadal jest /bin/rmtak, że naprawdę go potrzebuję).
Konrad Rudolph,


7

Poprzednie odpowiedzi wspominają polecenia trash-clii rmtrash. Żaden z nich nie jest domyślnie znaleziony w systemie Ubuntu 18.04, ale polecenie gioto. Wyjściowe polecenia gio help trash:

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

Move files or directories to the trash.

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

Przetestowałem za pomocą gio trash FILENAMEwiersza polecenia i działa tak, jakbym wybrał plik w przeglądarce plików i kliknąłem przycisk DEL: plik jest przenoszony do folderu Kosz na pulpicie. (Polecenie nie wyświetla monitu o potwierdzenie, mimo że nie skorzystałem z tej -fopcji).

Usuwanie plików w ten sposób jest odwracalny, będąc bardziej wygodne niż redefinicji rmbyć rm -idla bezpieczeństwa i konieczności potwierdzić każde usunięcie, która pozostawia ci pecha jeśli przypadkowo potwierdzić usunięcie nie powinno się mieć.

Dodałem alias tt='gio trash'do mojego pliku definicji aliasów; ttjest mnemonikiem To Trash.

Dodano podczas edycji w dniu 27.06.2018 r .: Na serwerach nie ma odpowiednika katalogu na śmieci. Napisałem następujący skrypt Bash, który wykonuje zadanie; na komputerach stacjonarnych używa gio trash, a na innych komputerach przenosi pliki podane jako parametry do utworzonego katalogu śmieci. Skrypt zaktualizowano 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

Jest to małe narzędzie o nazwie rmtrash, które to robi.

Wygląda na to, że nie reaguje na parametry takie jak -rlub -f(wydaje się, że zasadniczo przenosi katalog / do katalogu ~ / .Trash), ale nie zastępuje plików o tej samej nazwie (dodaje „Kopiuj” do pliki / katalogi o podobnych nazwach).

Aby zainstalować za pomocą naparu

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

github.com/nateshmbhat/rm-trash . „rm-trash”, obsługuje również zduplikowane nazwy plików i rekurencyjne usuwanie. Sprawdź to.
Natesh bhat

4

Oto szybki i brudny system kosza, który radzi sobie z konfliktami nazw, a nawet pozwala na usunięcie wielu plików na tej samej ścieżce, o ile nie usuniesz więcej niż jednego pliku na sekundę.

Ostrzeżenie: wpisałem ten kod bezpośrednio w przeglądarce. Prawdopodobnie jest zepsuty. Nie używaj go do danych produkcyjnych.

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
)

Znane problemy:

  • Nie radzi sobie z wdziękiem, jeśli spróbujesz usunąć ten sam plik kilka razy jednocześnie.
  • Katalog śmieci może stać się ogromny, pliki powinny być wysyłane do podkatalogów na podstawie pierwszych kilku cyfr skrótu.
  • trashpowinien radzić sobie z nowymi liniami w nazwach plików, ale untrashnie robi tego, ponieważ polega na nim, grepa nowe wiersze nie są wstawiane do pliku metadanych.

2

Zacznij od zdefiniowania move_to_trashfunkcji:

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

Następnie alias rmdo tego:

alias rm='move_to_trash'

Zawsze można zadzwonić stary rmuciekając go odwrotnym ukośnikiem, tak: \rm.

Nie wiem, jak opróżnić katalog kosza przy ponownym uruchomieniu (w zależności od systemu może być konieczne zajrzenie do rc*skryptów), ale warto również utworzyć cronzadanie, które okresowo opróżnia katalog.


2
Niestety, to była łatwa część…: /
Konrad Rudolph

Ten skrypt może również utworzyć plik tekstowy w ukrytym katalogu dla każdego pliku zawierającego katalog, w którym się znajdował. Skrypt przywracający może odczytać starą lokalizację i przenieść ją z powrotem.
ephsmith

Istnieje również ryzyko, że wiele usuniętych plików o tej samej nazwie zderzy się w katalogu kosza, a tylko ostatni „usunięty” przetrwałby, aby móc go odzyskać.
killermist,

@killermist, tak. Oczywiście trzeba by zrobić coś dodatkowego za pomocą polecenia move. Nazwij plik „trashed”, jak chcesz i zachowaj oryginalną ścieżkę: | To wszystko krzyczy „po co ponownie tworzyć koło”. Istnieją istniejące rozwiązania tego problemu.
ephsmith

Użyj także innego aliasu. Pracuj na innym komputerze bez aliasów, jedno połączenie do rmi tam twoje pliki. delmoże być lepszym wyborem.
glenn jackman

1

Możesz użyć mojego del:

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

del przenosi pliki do .del / podkatalogu (iz powrotem)

użycie: del [-v] [-u] plik (i)
       del [-v] -p [-r] [-d dni] [katalog]
       del [-v] -l
opcje: -v pełny tryb
         -u cofnij usunięcie plików
         -p czyść usunięte pliki [starsze niż -d dni]
         -r rekurencyjne (wszystkie podkatalogi)
         -l wyświetla listę usuniętych plików
przykłady: del * .tmp # usuń wszystkie pliki * .tmp
          del -u project.pl # undelete project.pl
          del -vprd 2 # pełne wyczyszczenie usuniętych plików starszych niż 2 dni

0

W KDE 4.14.8 użyłem następującego polecenia, aby przenieść pliki do kosza (tak jakby zostały usunięte w Dolphin):

kioclient move path_to_file_or_directory_to_be_removed trash:/

Dodatek I: Znalazłem o poleceniu za pomocą

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

Dodatek II: funkcja (następnie pobierz ją w pliku .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
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.