Зробіть `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.