hapus file tetapi kecualikan semua file dalam daftar


16

Saya perlu membersihkan folder secara berkala. Saya mendapatkan daftar file yang berisi teks, file mana yang diizinkan. Sekarang saya harus menghapus semua file yang tidak ada dalam file ini.

Contoh:

dont-delete.txt:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt

Folder saya do clean-up berisi ini sebagai contoh:

ls /home/me/myfolder2tocleanup/:

dontdeletethisfile.txt
reallyimportantfile.txt
neverdeletethis.txt
important.txt
this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Jadi file ini harus dihapus:

this-can-be-deleted.txt
also-waste.txt
never-used-it.txt

Saya mencari sesuatu untuk membuat perintah hapus dengan opsi untuk mengecualikan beberapa file yang disediakan oleh file.


Apakah ini pekerjaan rumah?
mook765

Saya harap Anda bukan gurunya. lol
Gujarat Santana

2
@ gujarat Kami bukan layanan pekerjaan rumah gratis, jadi komentarnya benar. Adapun pertanyaan itu sendiri, mungkin bermanfaat bagi orang lain, jadi sejauh ini terbuka.
Sergiy Kolodyazhnyy

@Serg, aku sangat setuju denganmu
Gujarat Santana

Jawaban:


8

The rmperintah komentar sehingga Anda dapat memeriksa dan memverifikasi bahwa itu bekerja sebagai diperlukan. Maka cukup beri komentar pada baris itu.

The check directorybagian akan memastikan Anda tidak sengaja menjalankan script dari direktori yang salah dan mengkritik file yang salah.

Anda dapat menghapus echo deletinggaris untuk menjalankan secara diam-diam.

#!/bin/bash

cd /home/me/myfolder2tocleanup/

# Exit if the directory isn't found.
if (($?>0)); then
    echo "Can't find work dir... exiting"
    exit
fi

for i in *; do
    if ! grep -qxFe "$i" filelist.txt; then
        echo "Deleting: $i"
        # the next line is commented out.  Test it.  Then uncomment to removed the files
        # rm "$i"
    fi
done

Saya mengedit kode Anda untuk menghindari penggunaan yang tidak bergunals dan menangkap hasil yang tidak berguna grepjika yang ingin Anda ketahui adalah apakah ada kecocokan atau tidak. Saya juga menggunakan pola string tetap untuk menghindari masalah melarikan diri.
David Foerster

@DavidFoerster Terima kasih atas kontribusinya. Namun, ketika Anda mengubah whileloop ke forloop Anda secara tidak sengaja mengubah iteration keydari ike f. dalam deklarasi, yang memecahkan kode. Aku telah memperbaikinya.
LD James

Ups, kekuatan kebiasaan. Saya cenderung menyingkat nama variabel shell untuk nama file f. ;-P (... dan +1 untuk jawaban Anda yang saya lupa sebelumnya.)
David Foerster

10

Skrip python ini dapat melakukan ini:

#!/usr/bin/env python3
import os
no_remove = set()
with open('./dont-delete.txt') as f:
     for line in f:
         no_remove.add(line.strip())

for f in os.listdir('.'):
    if f not in no_remove:
        print('unlink:' + f ) 
        #os.unlink(f)

Bagian penting adalah menghapus tanda komentar pada os.unlink()fungsi.

CATATAN : tambahkan skrip ini dan dont-delete.txtke skrip Anda dont-delete.txtsehingga keduanya ada dalam daftar, dan simpan di direktori yang sama.


1
Saya mengubah kode Anda untuk menggunakan daftar setalih - alih untuk O (1) alih-alih O (n) mencari di bagian kedua.
David Foerster

terima kasih atas bantuan Anda, saya biasanya seorang pria windows, tetapi jahitan python juga akan keren =)
stefan83

1
@ stefan83: Python berjalan dengan baik di Windows.
David Foerster

3

Inilah satu kalimat:

comm -2 -3 <(ls) <(sort dont_delete) | tail +2 | xargs -p rm
  1. ls mencetak semua file di direktori saat ini (dalam urutan diurutkan)
  2. sort dont_delete mencetak semua file yang tidak ingin kita hapus dalam urutan
  3. yang <()Operator ternyata string menjadi objek file seperti
  4. The commperintah membandingkan dua file pra-disortir dan print garis yang mereka berbeda
  5. menggunakan -2 -3flags menyebabkan commhanya mencetak baris yang terkandung dalam file pertama tetapi bukan yang kedua, yang akan menjadi daftar file yang aman untuk dihapus
  6. yang tail +2panggilan hanya untuk menghapus judul dari commoutput, yang berisi nama file input
  7. Sekarang kita mendapatkan daftar file untuk dihapus pada standar keluar. Kami menyalurkan output ini xargsyang akan mengubah aliran output menjadi daftar argumen rm. The -ppasukan pilihan xargsuntuk meminta konfirmasi sebelum mengeksekusi.

Terima kasih atas bantuan Anda, sekarang saya punya solusi!
stefan83

@gardenhead, saya lelah kode Anda tetapi menghapus semua file di direktori dan hanya menyimpan file pertama dan terakhir dalam daftar jangan-hapus. apakah Anda punya ide untuk masalah ini? Terima kasih sebelumnya.
Negar

1

FWIW sepertinya Anda bisa melakukan ini secara asli zsh, menggunakan (+cmd)kualifikasi glob.

Untuk mengilustrasikannya, mari kita mulai dengan beberapa file

 % ls
bar  baz  bazfoo  keepfiles.txt  foo  kazoo

dan file daftar putih

 % cat keepfiles.txt
foo
kazoo
bar

Pertama, baca daftar putih ke dalam array:

 % keepfiles=( "${(f)$(< keepfiles.txt)}" )

atau mungkin lebih baik

 % zmodload zsh/mapfile
 % keepfiles=( ${(f)mapfile[./keepfiles.txt]} )

(setara dengan mapfilebuilt-in bash - atau sinonimnya readarray). Sekarang kita dapat memeriksa apakah kunci (nama file) ada dalam array menggunakan ${keepfiles[(I)filename]}yang mengembalikan 0 jika tidak ditemukan kecocokan:

 % print ${keepfiles[(I)foo]}
1
 % print ${keepfiles[(I)baz]}
0
 %

Kita bisa menggunakan ini untuk membuat fungsi yang mengembalikan truejika tidak ada kecocokan untuk $REPLYdalam array:

% nokeep() { (( ${keepfiles[(I)$REPLY]} == 0 )); }

Akhirnya, kami menggunakan fungsi ini sebagai kualifikasi dalam perintah kami:

 % ls *(+nokeep)
baz  bazfoo  keepfiles.txt

atau, dalam kasus Anda

 % rm -- *(+nokeep)

(Anda mungkin ingin menambahkan nama file daftar putih itu sendiri ke daftar putih.)


0

Dengan asumsi bahwa bash shell Anda telah extglob shoptdisetel untuk aktif, berikut ini adalah alternatif yang agak lebih konservatif:

rm !($(tr \\n \| < keep.txt))

(... menyertai saran comm @ gardenhead yang sangat baik!)


0

Dengan asumsi tidak ada spasi putih (Spasi / Tab) di file Anda yang tercantum dalam file bernama list, maka Anda akan melakukan:

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \)

Cukup tambahkan -deleteke perintah di atas untuk menghapus file yang tidak ada di file daftar . Jika menemukan Anda tidak memiliki -deletepilihan yang dapat Anda gunakan rmdengan -execsebagai berikut:

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} \;

Atau gunakan -execdengan +terminator sebagai gantinya.

find /path/to -type f \( ! -name "list" $(printf ' -a ! -name %s\n' $(< list)) \) -exec echo rm {} +

echo hanya digunakan untuk pengeringan.


0

Kecuali jika output ls /home/me/myfolder2tocleanup/melebihi batas argumen shell maksimum ARG_MAX yaitu sekitar 2MB untuk Ubuntu, saya akan menyarankan yang berikut ini.


Implementasi perintah satu baris yang akan melakukan pekerjaan, adalah sebagai berikut:

  1. Salin dont-delete.txtfile ke direktori yang berisi file yang akan dihapus seperti:
cp dont-delete.txt /home/me/myfolder2tocleanup/
  1. cd ke direktori yang berisi file yang akan dihapus seperti:
cd /home/me/myfolder2tocleanup/
  1. Lakukan dry-run untuk menguji perintah dan membuatnya mencetak nama file yang terdeteksi dihapus tanpa benar-benar menghapusnya, seperti:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs echo | tr " " "\n"
  1. Jika Anda puas dengan hasilnya, hapus file dengan menjalankan perintah seperti ini:
ls -p | grep -v / | sed 's/\<dont-delete.txt\>//g' | sort | comm -3 - <(sort dont-delete.txt) | xargs rm

Penjelasan:

  • ls -pakan mencantumkan semua file dan direktori di direktori saat ini dan opsi -pakan menambahkan /ke nama direktori.
  • grep -v /akan mengecualikan direktori dengan menghapus semua item yang mengandung /nama mereka.
  • sed 's/\<dont-delete.txt\>//g'akan mengecualikan dont-delete.txtfile, sehingga tidak terhapus dalam proses.
  • sortakan, hanya untuk memastikan, mengurutkan sisa keluaran ls.
  • comm -3 - <(sort dont-delete.txt)akan mengurutkan dont-delete.txtfile, membandingkannya dengan output yang diurutkan lsdan mengecualikan nama file yang ada di keduanya.
  • xargs rmakan menghapus semua nama file yang tersisa di output yang sudah diproses ls. Ini berarti semua item dalam direktori saat ini akan dihapus kecuali untuk direktori , file yang terdaftar didont-delete.txt berkas dan yang dont-delete.txtfile itu sendiri

Di bagian dry-run:

  • xargs echo akan mencetak file yang harus dihapus.
  • tr " " "\n" akan menerjemahkan spasi menjadi baris baru agar lebih mudah dibaca.

-1

Saran saya adalah:

sed -e 's/^/\.\//' dont-delete.txt > dont-delete-relative-path.txt
find . -type f -print | grep -Fxvf dont-delete-relative-path.txt | xargs -d'\n' rm

Perbarui 2018-08-07

Contoh:

1: mkdir /tmp/delete-example && cd /tmp/delete-example
2: touch a b c d
3: echo "./a\n./b\n./dont-delete.txt\n" > dont-delete.txt
4: find . -type f -print | grep -Fxvf dont-delete.txt | xargs -d'\n' rm

Catatan setelah baris 3 Anda akan memiliki dont-delete.txtfile dengan konten:

./a
./b
./dont-delete.txt

(yang utama ./adalah sangat penting )

File-file cdan dakan dihapus.


Saya mencoba ini dengan file teks dari nama file yang dipisahkan oleh baris baru. Itu akhirnya menghapus semua file dalam direktori.
Jacques MALAPRADE

Saya kira "simpan daftar" Anda salah.
nyxz

Saya telah menambahkan contoh penggunaan.
nyxz
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.