Cofnij akcję polecenia kopiowania (cp)


14

Skopiowałem jakiś plik z folderu źródłowego do folderu docelowego za pomocą poniższego wiersza poleceń w terminalu.

sudo cp From_SOURCE/* To_DESTINATION/

Teraz chcę cofnąć to polecenie.


Nie jestem pewien, czy rozumiem. Po prostu usunąć kopię? (plik sudo rm)
— Jacob Vlijm

@JacobVlijm to nie jest cofnięcie akcji, to osobne polecenie. Gdybym nie skopiował, mógłbym wcześniej użyć sugerowanego polecenia. I muszę coraz więcej czasu używać tego polecenia, aby usunąć ponad 1000 skopiowanych plików?
— αғsнιη

@KasiyA - opcją byłoby znaleźć wszystkie wybrane nazwy plików From_SOURCE/*i usunąć je To_DESTINATION/; można to zrobić za pomocą bash - tutaj problemy mogą polegać na tym, że polecenie cp nadpisało wszystko, dowiązania symboliczne zostały skopiowane, pliki ze spacjami w nazwach itp. - więc mogło to mieć problemy i nieco zwariowane. Idealna opcja „cofnij” mogłaby uwzględniać wiele rzeczy.
— Wilf,

Odpowiedzi:


13

Jeśli dobrze rozumiem, dzieje się tak:

  • Skopiowałeś (prawdopodobnie dużą) liczbę plików do istniejącego katalogu i potrzebujesz / chcesz cofnąć akcję.
  • Docelowy katalog zawiera wiele innych plików, które musisz tam przechowywać, co uniemożliwia po prostu usunięcie wszystkich plików z katalogu

Poniższy skrypt wyszukuje w oryginalnym katalogu (źródłowym) i wyświetla te pliki. Następnie przegląda katalog, do którego skopiowano pliki, i usuwa tylko wymienione pliki, ponieważ istnieją one w katalogu źródłowym.

tryElement jest dodawany, aby zapobiec błędom, na przykład w przypadku mogłeś usunięto niektóre pliki ręcznie już, lub jeśli nie wszystkie pliki z katalogu źródłowego zostały skopiowane do miejsca przeznaczenia. Jeśli potrzebujesz uprawnień sudo, po prostu uruchom skrypt z „sudo” (patrz poniżej).

Scenariusz

#!/usr/bin/env python

import os

source_dir = "/path/to/source" # the folder you copied the files from
target_folder = "/path/to/destination" # the folder you copied the files to

for root, dirs, files in os.walk(source_dir):
    for name in files:
        try:
            os.remove(target_folder+"/"+name)
        except FileNotFoundError:
            pass

Jak używać

  • Wklej skrypt do pustego pliku, zapisz go jako reverse.py,
  • Wstaw poprawne ścieżki do folderu źródłowego i docelowego,
  • Zrób to ze względów wygody,
  • Uruchom go za pomocą polecenia:

    [sudo] /path/to/reverse.py
    

Ostrzeżenie

Najpierw wypróbuj katalog testowy, jeśli dobrze rozumiem, co musisz osiągnąć!


Jeśli katalog jest „płaski”

W przypadku, gdy katalog źródłowy nie ma podkatalogów, skrypt może być jeszcze prostszy:

#!/usr/bin/env python

import os

source_dir = "/path/to/source" # the folder you copied the files from
target_folder = "/path/to/destination" # the folder you copied the files to

for file in os.listdir(source_dir):
    try:
        os.remove(target_folder+"/"+file)
    except FileNotFoundError:
        pass

Uwaga

Jeśli akcja kopia nadpisałeś (zastąpiony) plik o podobnej nazwie w okolicy, plik zostanie usunięty, ale oryginalny plik (oczywiście) nie może być sprowadzony przez skrypt. Zakłada się, że nie ma konfliktów nazw.


Działa, dziękuję. Prowadzę to sudo python3 reverse.py. Przyjmuję twoją odpowiedź.
— αғsнιη

Doskonały! Dziękuję za miłe pytanie, które opisuje sytuację, w której prawdopodobnie wszyscy byliśmy :)
— Jacob Vlijm

Uwaga: Jeśli jakikolwiek plik w źródle nadpisał plik w miejscu docelowym, ponieważ miał taką samą nazwę, nie można tego po prostu cofnąć , a ten skrypt po prostu go usunie. Zakłada się tutaj, że podczas inicjowania nie było żadnych konfliktów nazw cp.
— thomasrutter

@neon_overload Prawidłowo, edytowałem to w mojej odpowiedzi.
— Jacob Vlijm

To nie działa dla cp -r. Zmieniłem za os.removepomocą print, i wyprowadza kilka plików, które nie istnieją. Zakładam, że brakuje podkatalogów i tylko listy plików na końcu.
— Typewar

7

TL; DR:

Wszystkie pliki, które są obecne w obu srci destmożna je usunąć w destnastępujący sposób:

find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;

Aby uzyskać wyjaśnienie krok po kroku, patrz poniżej.

Uproszczenie problemu:

Aby zrozumieć, co właściwie zrobiliśmy polecenie, zaczynamy od uproszczenia:

Polecenie, które chcemy cofnąć, to

sudo cp From_SOURCE/* To_DESTINATION/

Dla zrozumienia, jak cofnąć, sudonie ma znaczenia.

Użyję nazw katalogów srcdla From_SOURCEi destdla To_DESTINATION.

Teraz naszym poleceniem jest:

cp src/* dest/

Jeśli srczawiera pliki f1, f2a f3, a katalogi d1i d2, powłoka rozszerza tę komendę:

cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/

Bez opcji podoba -r, -Rczy -akomenda cpnie kopiuje katalogów.
Oznacza to, że polecenie je pominie, pokazując błąd dla każdego z nich:

$ cp src/f1 src/f2 src/f3 src/d1 src/d2 dest/
cp: omitting directory 'src/d1'
cp: omitting directory 'src/d2'

Oznacza to, że skopiowaliśmy tylko proste pliki, a nie katalogi dest.

Decydowanie, które pliki usunąć:

Możliwe, że były pliki desto tej samej nazwie co pliki src. W tym przypadku pliki zostały nadpisane (1). Przepraszam, jest już dla nich za późno. Odzyskaj je z najnowszej kopii zapasowej.

Jeśli chodzi o pliki, które tam są, chcemy usunąć tylko pliki, które zostały skopiowane. Pliki te istnieją w obu katalogach, o tej samej nazwie i tej samej zawartości.

Szukamy więc tych plików:

Po pierwsze, wchodzimy cdw to src, ponieważ findznacznie upraszcza następujące polecenia i ustawia zmienną na absolutną ścieżkę dest:

$ cd src
$ destdir="$(readlink -f dest)"

Następnie wyświetlamy wszystkie pliki w src:

$ find . -maxdepth 1 -type f

i dla każdego znalezionego pliku użyj, cmpaby sprawdzić, czy w dest jest plik o tej samej zawartości:

$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -print

Usuwając pliki, ostrożnie:

Te pliki chcemy usunąć. Ale dla pewności najpierw przenosimy je do innego katalogu - i uruchamiamy polecenia przed ich uruchomieniem:

$ toDelete=/tmp/toDelete ; mkdir -p "$toDelete"
$ find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec echo mv -n "$destdir/{}" "$toDelete"/ \;
mv -n /path/to/dest/./f1 /tmp/toDelete/`
mv -n /path/to/dest/./f2 /tmp/toDelete/`
mv -n /path/to/dest/./f3 /tmp/toDelete/`

Wygląda dobrze! Teraz możemy pominąć echouruchamianie prawdziwych mvpoleceń:

find . -maxdepth 1 -type f -exec cmp -s '{}' "$destdir/{}" \; -exec mv -n "$destdir/{}" "$toDelete"/ \;

Wszystkie pliki z desttego zostały skopiowane srci nadal są takie same w srci destsą teraz w /tmp/toDelete/i można je usunąć po ostatnim spojrzeniu.


Uwagi:
(1) Sprawdź, czy cpjest to alias do, czy coś cp -itakiego, aby zapobiec zastąpieniu plików, pytając najpierw.


5

To jest stare, ale chciałem tylko napisać czystą odpowiedź:

Najpierw przejdź do katalogu, w którym skopiowano pliki.

cd dest

Następnie lskatalog źródłowy i potokuj dane wyjściowerm

ls source | xargs rm


2
parsowanie lsjest zazwyczaj złym pomysłem. mywiki.wooledge.org/ParsingLs Nie będę głosować za twoim postem, ale należy to zauważyć.
— Sergiy Kolodyazhnyy 17.07.16

@SergiyKolodyazhnyy good point. Niemniej jednak: rm `ls`—dla pustego wcześniej folderu i gdy pliki mają nazwy bez spacji i znaków nowej linii.
— Multifix
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.