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.)

Konrad Rudolph
fonte
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
zpea
fonte
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
9

O Trash-cli é um aplicativo linux que pode ser instalado usando o apt-get no Ubuntu ou yum no Fedora. O uso do comando trash listOfFilesmoverá o especificado para a lixeira.

namu
fonte
Para apoiar esta sugestão: apple.stackexchange.com/a/17637/37190
Ioannis Filippidis
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
Teemu Leisti
fonte
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
FreePender
fonte
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.
Gilles 'SO- parar de ser mau'
fonte
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.

rahmu
fonte
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
Framstag
fonte
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
}
user3804598
fonte