Зробіть `rm` перемістити у смітник


54

Чи існує скрипт / додаток Linux, який замість видалення файлів переміщує їх у спеціальне місце "сміття"? Я хотів би це зробити заміною rm(можливо, навіть згладжування останнього; для цього є плюси і мінуси).

Під "сміттям" я маю на увазі спеціальну папку. Сингл mv $* ~/.trash- це перший крок, але в ідеалі для цього слід також переробити кілька однойменних файлів без перезапису старих пошкоджених файлів та дозволити відновити файли у вихідне місце за допомогою простої команди (свого роду «скасувати»). Крім того, було б непогано, якби сміття було автоматично видалено під час перезавантаження (або подібний механізм для запобігання нескінченного зростання).

Часткові рішення для цього існують, але, зокрема, дія "відновлення" не є тривіальною. Чи існують для цього рішення, які не покладаються на сміттєву систему з графічної оболонки?

(Окрім того, існували нескінченні дискусії щодо того, чи є такий підхід виправданим, а не використовувати часті резервні копії та VCS. Хоча ці дискусії мають сенс, я вважаю, що все ще є ніша для мого запиту.)


4
Це може бути пов'язано з питанням SuperUser Дві команди для переміщення файлів у кошик. Яка різниця? . Раніше я використовував gvfs-trash, але ніколи не потребував відновлення з командного рядка, поки ти не викликав моєї цікавості. Відповідь на пов'язане питання може бути корисною.
— ephsmith

1
@ephsmith Спасибі, гарне посилання. Проблема цих підходів полягає в тому, що вони пов'язані з певними оболонками робочого столу (який тут правильний термін?), Чого я хочу уникати.
— Конрад Рудольф

1
Чи переміщується файли з будь-якої файлової системи до вашого ~ навмисного? Тому що одного дня ви можете видалити ізо-образ із розміром 4 ГБ, що зберігається на dir, встановленому на sshfs, із дійсно віддаленого сервера.
— Mischa Arefiev

1
@Mischa Якщо чесно кажучи, я не задумувався над цим. З цього приводу вона повинна працювати із звичайними правами користувача, тому цільовим розташуванням повинно бути місце, яке можна записати і не повинно вимагати занадто великої конфігурації.
— Конрад Рудольф

3
Робіть все, що завгодно, як-от рішення, викладені у відповідях нижче, але не називайте це rm. Як вказували інші, перейменування / перестановка стандартних команд залишає вас вразливими, коли ви звично намагаєтесь їх використовувати в інших системах, але це також спричинить проблеми для інших (можливо, допоможе вам) за допомогою вашої системи / облікового запису, коли трапляються несподівані результати.
— Джо

Відповіді:


37

На freedesktop.org є специфікація (чернетка) для кошика . Це, мабуть, те, що зазвичай реалізується на робочому столі.

Реалізація командного рядка буде trash-cli . Не маючи уважнішого огляду, це, здається, забезпечує необхідну функціональність. Якщо ні, то скажіть нам, наскільки це лише часткове рішення.

Що стосується використання будь-якої програми в якості заміни / псевдоніма для rm, є вагомі причини цього не робити. Найбільш важливі для мене:

  • Програмі потрібно було б зрозуміти / впоратися з усіма rmваріантами і діяти відповідно
  • Це ризикує звикнути до семантики вашого "нового RM" та виконувати команди зі смертельними наслідками під час роботи над чужими системами

Також є лібраш, який автоматично переміщує всі видалені файли у кошик через LD_PRELOAD (але, здається, має кілька помилок). Автомобільний сміття допомагає легко очистити сміття.
— jofel

Мені цікаво про те, як увійти в звичку використовувати-rm. Я вже за звичкою, на жаль.
— Конрад Рудольф

@jofel: Лібтраш має дійсно приємну концепцію. На кілька шарів глибше, ніж інші підходи. Шкода, що він баггі (і здається не дуже активним).
— zpea

4
@KonradRudolph: Я мав на увазі, що людина звикає до того, що rm (замінений) насправді нічого не видаляє, так що можна менш обережно, оскільки відновлення завжди можливо. Звичайно, саме використання rm - це не погано, а також до нього не звикаєш.
— zpea

4
Я в кінцевому підсумку скористався цим рішенням і відключив його, rmтому я не можу його використати випадково (все ще є /bin/rmна випадок, якщо він мені справді потрібен).
— Конрад Рудольф


7

У попередніх відповідях згадуються команди trash-cliта rmtrash. Жоден з них не знайдений за замовчуванням на Ubuntu 18.04, але команда gioє. Командні 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

Я перевірив, використовуючи gio trash FILENAMEкомандний рядок, і він працює так, як я вибрав файл у браузері файлів і натиснув кнопку DEL: файл переміщений у папку сміття робочого столу. (Команда не вимагає підтвердження, навіть якщо я не використовував цю -fопцію.)

Видалення файлів таким чином , є оборотним, в той же час більш зручно , ніж перевизначення rmбути rm -iдля безпеки і того , щоб підтвердити видалення кожного, який по- , як і раніше залишає вас не пощастило , якщо ви випадково підтвердження видалення ви не повинні мати.

Я додав alias tt='gio trash'у свій файл визначення псевдонімів; ttє мнемічним для кошика.

Додано в редагування 2018-06-27: На серверних машинах немає еквівалента каталогу сміття. Я написав наступний сценарій Баша, який виконує цю роботу; на настільних машинах він використовує gio trashта на інших машинах переміщує файли (файли), задані як параметри (а), у створений ним каталог сміття. Сценарій оновлено 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

5

Існує невелика утиліта під назвою rmtrash, яка робить це.

Він, схоже, не реагує на парами типу ( -rабо -f(здається, що це фактично просто переміщення файлу / каталогу в каталог ~ / .Trash)), але не замінить файли з тим самим іменем (додається "Копіювати" в файли / каталоги з назвою).

Встановити заваркою

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

github.com/nateshmbhat/rm-trash . "rm-trash" також обробляє дублюючі імена файлів і рекурсивні видалення. Перевір.
— Natesh bhat

4

Ось швидка та брудна система сміття, яка справляється зі зіткненнями імен та навіть дозволяє декілька видалених файлів на одному шляху до тих пір, поки ви не видалите більше одного файлу в секунду.

Попередження: Я ввів цей код прямо у свій браузер. Це, мабуть, зламано. Не використовуйте його на виробничих даних.

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
)

Відомі проблеми:

  • Не справляється витончено, якщо ви намагаєтесь одночасно видалити один і той самий файл.
  • Каталог сміття може стати величезним, файли повинні бути відправлені в підкаталоги на основі перших кількох цифр хеша.
  • trashповинен справлятися з новими рядками в іменах файлів, але untrashне тому, що на нього покладаються, grepа нові рядки не залишаються у файлі метаданих.

2

Почніть з визначення move_to_trashфункції:

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

Тоді псевдонім rmдо цього:

alias rm='move_to_trash'

Ви завжди можете зателефонувати старим rmвитікання його з зворотної косої межі, наприклад: \rm.

Я не знаю, як зробити каталог сміття порожнім під час перезавантаження (залежно від вашої системи, можливо, доведеться зазирнути в rc*сценарії), але також може бути варто створити cronзавдання, яке періодично очищає каталог.


2
На жаль, це була легка частина…: /
— Конрад Рудольф

Цей скрипт також може створити текстовий файл у прихованій папці для кожного файлу, який містить каталог, у якому він був. Сценарій відновлення міг прочитати старе місце та перемістити його назад.
— ephsmith

Це також має небезпеку того, що декілька видалених файлів з тим самим іменем зіткнуться у каталозі сміття, і лише останній "видалений" вижив би, щоб його можна було відновити.
— вбивця

@killermist, так. Звичайно, потрібно було б зробити щось додаткове з командою переміщення. Назвіть файл "кошик", що вам потрібно, і збережіть початковий шлях: | Це все кричить "навіщо створювати колесо". Існують існуючі рішення цієї проблеми.
— ephsmith

Також використовуйте інше псевдонім. Працюйте на іншій машині без псевдонімів, один дзвінок туди rmі надсилайте свої файли. delможе бути кращим вибором.
— glenn jackman

1

Ви можете використовувати мій дель:

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

del переміщує файли у .del / підкаталог (і назад)

використання: del [-v] [-u] файл (и)
       del [-v] -p [-r] [-d днів] [каталог]
       дель [-в] -л
параметри: -v багатослівний режим
         -у відновити файли
         -p очищення видалених файлів [старше -d днів]
         -r рекурсивний (усі підкаталоги)
         -перелік видалених файлів
приклади: del * .tmp # видалити всі * .tmp файли
          del -u project.pl # undelete project.pl
          del -vprd 2 # багатослівна чистка видалених файлів старше 2 днів

0

У KDE 4.14.8 я використовував таку команду для переміщення файлів у кошик (як би він був видалений у Dolphin):

kioclient move path_to_file_or_directory_to_be_removed trash:/

Додаток I: Я знайшов про команду с

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

Додаток II: функція (потім джерело її у вашому .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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.