使“ rm”移至垃圾箱


54

是否有Linux脚本/应用程序,而不是删除文件,而是将其移动到特殊的“垃圾箱”位置?我希望以此作为替代rm(甚至可以别名后者;对此有优缺点)。

“垃圾箱”是指一个特殊的文件夹。单mv $* ~/.trash是第一步,但理想的,这也应该处理捣毁了多个同名的文件,而不会覆盖旧的丢弃的文件,并允许恢复文件到原始位置用一个简单的命令(一种“撤消”)。此外,如果垃圾桶在重新启动时自动清空(或采用类似的机制来防止不断增长的垃圾),那就太好了。

存在对此的部分解决方案,但是特别是“恢复”动作并非微不足道。是否有不依赖图形外壳垃圾系统的现有解决方案?

(顺便说一句,关于这种方法是否合理,一直在进行无休止的讨论,而不是使用频繁的备份和VCS。尽管这些讨论是有道理的,但我认为我的要求仍然存在。)


4
这可能与超级用户问题“ 两个将文件移至回收站的命令”有关有什么不同?。我过去使用gvfs-trash过,但是直到您激发了我的好奇心,才从命令行恢复它。链接问题的答案可能会有所帮助。
ephsmith 2012年

1
@ephsmith谢谢,很好的链接。但是,这些方法的问题是它们绑定到特定的桌面外壳程序(这里是正确的术语?)实现,我想避免这种事情。
康拉德·鲁道夫2012年

1
是否将文件从任何文件系统移动到您的〜?因为有一天您可能会从真正的远程服务器上删除驻留在sshfs挂载的目录中的4GB iso映像。
米沙·阿列菲耶夫

1
@Mischa老实说,我并没有考虑太多。也就是说,它应该与通常的用户权限一起使用,因此目标必须是可写的位置,并且不需要太多配置。
Konrad Rudolph

3
做任何您想做的事情,例如以下答案中概述的解决方案,但不要将其命名为rm。正如其他人指出的那样,重命名/重新使用标准命令会使您在习惯性地尝试在其他系统上使用它们时容易受到攻击,但是当意外结果发生时,这也会给使用您的系统/帐户的其他任何人(可能是协助您)带来麻烦。

Answers:


37

freedesktop.org上有一个“垃圾桶”规范(草稿)。显然,这通常是由桌面环境实现的。

命令行实现将是trash-cli。如果不仔细看,它似乎可以提供您想要的功能。如果不是,请告诉我们这仅是部分解决方案。

至于使用任何程序作为替换/别名rm,有充分的理由不这样做。对我来说最重要的是:

  • 该程序需要理解/处理所有rm的选项并采取相应措施
  • 在其他人的系统上工作时,它可能会习惯于“新rm”的语义并执行具有致命后果的命令

还有一个libtrash,它通过LD_PRELOAD将所有已删除的文件自动移到垃圾桶(但似乎有几个错误)。自动垃圾桶有助于轻松清理垃圾。
jofel 2012年

我想知道使用RM的习惯。不幸的是,我已经养成了习惯。
Konrad Rudolph

@jofel:libtrash有一个非常好的概念。比其他方法要深几层。可惜它是越野车(而且似乎不太活跃)。
zpea

4
@KonradRudolph:我的意思是说,一个人已经习惯了rm(被替换的rm)并没有真正删除任何内容,因此不必那么小心,因为还原始终是可能的。当然,使用rm本身并不是一件坏事,也不习惯。
zpea

4
我最终使用了该解决方案,并且将其禁用,rm因此我不会意外使用它(仍然可以/bin/rm在需要时使用)。
康拉德·鲁道夫2012年


7

前面的答案提到了命令trash-clirmtrash。在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按钮一样:该文件已移动到桌面的“废纸folder”文件夹中。(即使我没有使用该-f选项,该命令也不会提示您进行确认。)

以这种方式删除文件是可逆的,同时为了安全起见,重新定义rm要方便得多rm -i,并且必须确认每个删除操作,如果您不小心确认了不应该删除的删除操作,这仍然使您不走运。

我添加alias tt='gio trash'了别名定义文件;tt是“废纸To”的助记符。

在2018-06-27上的编辑中添加:在服务器计算机上,没有等效的废纸 a目录。我编写了以下Bash脚本来完成这项工作;在台式计算机上,它使用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安装

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
不幸的是,这是最简单的部分……:/
康拉德·鲁道夫

该脚本还可以在每个包含隐藏目录的文件的隐藏目录中创建一个文本文件。还原脚本可以读取旧位置并将其移回。
伊夫史密斯2012年

这也有一个危险,即多个具有相同名称的已删除文件将在回收站目录中冲突,并且只有最后一个“已删除”文件可以生存下来,才能恢复。
killermist 2012年

@killermist,是的。当然,将需要对move命令执行其他操作。根据需要命名“ trashed”文件,并保留原始路径:| 这一切都在尖叫“为什么要重新制造轮子”。有解决此问题的现有方法。
伊夫史密斯2012年

另外,请使用其他别名。在没有别名的情况下在另一台机器上工作,一次调用rm并保存文件。del可能是一个更好的选择。
glenn jackman'7

1

您可以使用我的del:

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

del将文件移动到.del /子目录中(并移回)

用法:del [-v] [-u]文件
       删除[-v] -p [-r] [-d天] [目录]
       删除[-v] -l
选项:-v详细模式
         -u取消删除文件
         -p清除已删除的文件[早于-d天]
         -r递归(所有子目录)
         -l列出已删除的文件
示例:del * .tmp#删除所有* .tmp文件
          del -u project.pl#取消删除project.pl
          del -vprd 2#清除2天以上的已删除文件

0

在KDE 4.14.8中,我使用以下命令将文件移至垃圾箱(就像在Dolphin中将其删除一样):

kioclient move path_to_file_or_directory_to_be_removed trash:/

附录一:我发现与

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

附录二:函数(然后在.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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.