Faça o `rm` mover para o lixo


54

Existe um script / aplicativo Linux que, em vez de excluir arquivos, os move para um local especial de "lixo"? Eu gostaria disso como um substituto para rm(talvez até apelidado o último; existem prós e contras para isso).

Por "lixo", quero dizer uma pasta especial. Um mv $* ~/.trashé o primeiro passo, mas, idealmente, isso também deve lidar com a lixeira de vários arquivos com o mesmo nome, sem sobrescrever os arquivos lixeira mais antigos, e permitir restaurar os arquivos no local original com um comando simples (uma espécie de "desfazer"). Além disso, seria bom se o lixo fosse esvaziado automaticamente na reinicialização (ou um mecanismo semelhante para impedir o crescimento sem fim).

Existem soluções parciais para isso, mas a ação de "restauração" em particular não é trivial. Existe alguma solução para isso que não dependa de um sistema de lixo de um shell gráfico?

(À parte, houve inúmeras discussões sobre se essa abordagem é justificada, em vez de usar backups freqüentes e VCS. Embora essas discussões tenham razão, acredito que ainda haja um nicho para minha solicitação.)


4
Isso pode estar relacionado à pergunta do superusuário Dois comandos para mover arquivos para a lixeira. Qual é a diferença? . Eu usei gvfs-trashno passado, mas nunca tive a necessidade de restaurar a partir da linha de comando até que você despertou minha curiosidade. A resposta para a pergunta vinculada pode ser útil.
— ephsmith

11
@ephsmith Obrigado, bom link. O problema com essas abordagens é que elas estão vinculadas a implementações específicas do shell da área de trabalho (qual é o termo correto aqui?), Algo que eu quero evitar.
— 21320 Konrad Rudolph

11
A movimentação de arquivos de qualquer sistema de arquivos para o seu ~ é intencional? Porque um dia você pode excluir uma imagem iso de 4 GB residindo em um diretório montado com sshfs de um servidor realmente remoto.
— Mischa Arefiev

11
@Mischa Para ser sincero, não pensei muito nisso. Dito isso, ele deve funcionar com os direitos usuais do usuário, para que o destino precise ser um local gravável e não exija muita configuração.
— 21911 Konrad Rudolph

3
Faça o que quiser, como as soluções descritas nas respostas abaixo, mas não o nomeie. Conforme indicado por outras pessoas, renomear / redirecionar comandos padrão o deixa vulnerável quando você costuma usá-los em outros sistemas, mas também causa problemas para qualquer outra pessoa (talvez ajudando você) a usar seu sistema / conta quando ocorrem resultados inesperados.
— 31412 Joe

Respostas:


37

Há uma especificação (rascunho) para o Lixo no freedesktop.org. Aparentemente, é o que geralmente é implementado pelos ambientes de desktop.

Uma implementação de linha de comando seria lixo-cli . Sem ter um olhar mais atento, parece fornecer a funcionalidade que você deseja. Caso contrário, diga-nos até que ponto isso é apenas uma solução parcial.

No que diz respeito ao uso de qualquer programa como substituto / alias rm, há boas razões para não fazer isso. Os mais importantes para mim são:

  • O programa precisaria entender / manipular todas rmas opções e agir em conformidade
  • Ele corre o risco de se acostumar com a semântica da sua "nova rm" e executar comandos com consequências fatais ao trabalhar nos sistemas de outras pessoas

Também existe o libtrash que move todos os arquivos excluídos automaticamente para o lixo via LD_PRELOAD (mas parece ter vários bugs). O Autotrash ajuda a limpar o lixo de maneira fácil.
— Jofel

Eu estou pensando sobre o coisinho de usar o hábito. Eu já tenho o hábito, infelizmente.
— 11133 Konrad Rudolph

@ jofel: libtrash tem um conceito muito bom. Algumas camadas mais profundas que as outras abordagens. É uma pena que seja buggy (e não parece muito ativo).
— Zpea

4
@KonradRudolph: Eu quis dizer que alguém se acostuma ao fato de que o rm (o substituído) não exclui nada, de modo que se tem menos cuidado, pois sempre é possível restaurar. Obviamente, usar o rm em si não é algo ruim, nem está se acostumando.
— Zpea

4
Acabei usando esta solução e desativando rmpara não poder usá-la acidentalmente (ainda há /bin/rmcaso eu realmente precise dela).
— precisa saber é o seguinte


7

As respostas anteriores mencionam comandos trash-clie rmtrash. Nenhum deles é encontrado por padrão no Ubuntu 18.04, mas o comando gioé. Comandando gio help trashsaídas:

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

Move files or directories to the trash.

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

Eu testei usando gio trash FILENAMEna linha de comando e funciona como se eu tivesse selecionado o arquivo no navegador de arquivos e clicado no botão DEL: o arquivo é movido para a pasta Lixeira da área de trabalho. (O comando não solicita confirmação, embora eu não tenha usado a -fopção.)

A exclusão de arquivos dessa maneira é reversível, embora seja mais conveniente do que redefinir rmpara garantir rm -ia segurança e ter que confirmar cada exclusão, o que ainda deixa você sem sorte se confirmar acidentalmente uma exclusão que não deveria ter.

Eu adicionei alias tt='gio trash'ao meu arquivo de definições de alias; tté um mnemônico para To Trash.

Adicionado na edição em 27/06/2018: nas máquinas servidoras, não há equivalente a um diretório da lixeira. Eu escrevi o seguinte script Bash que faz o trabalho; em máquinas de mesa, ele usa gio trashe em outras máquinas move os arquivos fornecidos como parâmetros para um diretório de lixo que ele cria. Script atualizado em 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

Há um pequeno utilitário chamado rmtrash que faz isso.

Parece não responder a parâmetros como -rou -f(parece estar apenas movendo o arquivo / diretório para o diretório ~ / .Trash), mas não substitui arquivos com o mesmo nome (acrescenta "Copiar" a arquivos / diretórios com nomes semelhantes).

Para instalar com o brew

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

github.com/nateshmbhat/rm-trash . "rm-lixo", lida com nomes de arquivos duplicados e exclusões recursivas também. Confira.
— Natesh bhat

4

Aqui está um sistema de lixo rápido e sujo que lida com conflitos de nome e até permite vários arquivos excluídos no mesmo caminho, desde que você não exclua mais de um arquivo por segundo.

Aviso: digitei esse código diretamente no meu navegador. Provavelmente está quebrado. Não use em dados de produção.

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
)

Problemas conhecidos:

  • Não lida normalmente se você tentar excluir o mesmo arquivo várias vezes simultaneamente.
  • O diretório da lixeira pode ficar enorme, os arquivos devem ser despachados em subdiretórios com base nos primeiros dígitos do hash.
  • trashdeve lidar com novas linhas nos nomes de arquivos, mas untrashnão porque depende grepe as novas linhas não são escapadas no arquivo de metadados.

2

Comece definindo uma move_to_trashfunção:

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

Depois, alias rmpara isso:

alias rm='move_to_trash'

Você pode sempre chamar idade rmescapando-lo com uma barra invertida, como este: \rm.

Não sei como tornar o diretório da lixeira vazio na reinicialização (dependendo do sistema, talvez seja necessário pesquisar nos rc*scripts), mas também pode valer a pena criar uma crontarefa que esvazie o diretório periodicamente.


2
Infelizmente, essa foi a parte fácil ...: /
— Konrad Rudolph

Esse script também pode criar um arquivo de texto em um diretório oculto para cada arquivo que contém o diretório em que estava. Um script de restauração pode ler o local antigo e movê-lo de volta.
— ephsmith

Isso também corre o risco de vários arquivos excluídos com o mesmo nome colidirem no diretório da lixeira, e apenas o último "excluído" sobreviveria para poder ser recuperado.
— Killermist

@killermist, sim. É claro que seria necessário fazer algo adicional com o comando move. Nomeie o arquivo "lixeira" como desejar e mantenha o caminho original: | Tudo isso grita "por que recriar a roda". Existem soluções existentes para esse problema.
— ephsmith

Além disso, use um nome de alias diferente. Trabalhe em outra máquina sem seus pseudônimos, uma chamada para rme seus arquivos. delpode ser uma escolha melhor.
— Glenn Jackman

1

Você pode usar meu del:

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

del move arquivos em um subdiretório .del (e vice-versa)

use: del [-v] [-u] arquivo (s)
       del [-v] -p [-r] [-d dias] [diretório]
       del [-v] -l
opções: -v modo detalhado
         -u recuperar arquivos
         -p exclui arquivos excluídos [anteriores a -d dias]
         -r recursivo (todos os subdiretórios)
         -l lista arquivos excluídos
exemplos: del * .tmp # exclui todos os arquivos * .tmp
          del -u project.pl # undelete project.pl
          del -vprd 2 # limpeza detalhada de arquivos excluídos com mais de 2 dias

0

No KDE 4.14.8, usei o seguinte comando para mover arquivos para a lixeira (como se tivessem sido removidos no Dolphin):

kioclient move path_to_file_or_directory_to_be_removed trash:/

Apêndice I: Encontrei sobre o comando com

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

Apêndice II: a função (depois forneça-a no seu .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
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.