Hapus semua file dalam direktori yang namanya tidak cocok dengan baris dalam daftar file

9

Saya memiliki direktori dengan 1000+ file. Dalam file teks, saya memiliki sekitar 50 nama file, satu nama per baris. Saya ingin menghapus semua file dalam direktori yang nama filenya tidak sesuai dengan entri pada daftar. Apa cara terbaik untuk melakukan ini? Saya memulai skrip shell, tetapi tidak bisa menentukan perintah yang tepat untuk menentukan dalam nama file ada di daftar. Terima kasih.

Nathan
sumber

Jawaban:

8

Saya menyadari bahwa pertanyaan apa pun yang menanyakan cara menghapus file harus diambil dengan sangat hati-hati. Jawaban pertama saya terlalu tergesa-gesa saya tidak mengambil fakta bahwa filelist dapat cacat untuk digunakan dengan egrep. Saya mengedit jawaban untuk mengurangi risiko itu.

Itu harus bekerja untuk file yang tidak memiliki ruang dalam nama:

Pertama-tama buat ulang filelist Anda untuk memastikan agar sesuai dengan nama file yang tepat:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

membangun perintah rm

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

Periksa apakah skrip rm cocok untuk Anda (Anda dapat melakukannya dengan "vim" atau "kurang").
Kemudian lakukan tindakan:

sh -x rmscript

Jika file memiliki spasi dalam namanya (jika file memiliki "nama maka ini tidak akan berfungsi):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

tentu saja daftar file tidak boleh berada di direktori yang sama!

Diedit:

Daftar file Nathan berisi nama-nama yang cocok dengan semua file dalam direktori (seperti "html" cocok dengan "bob.html"). Jadi tidak ada yang dihapus karena egrep -vfmenyerap semua aliran. Saya menambahkan perintah untuk meletakkan "^" dan "$" di sekitar setiap nama file. Saya beruntung di sini bahwa daftar file Nathan benar. Apakah itu telah diformat DOS dengan garis akhir CR-LF atau dengan ruang tambahan, tidak ada file yang akan disimpan oleh egrep dan semua telah dihapus.

Emmanuel
sumber
Ketika saya menjalankan perintah pratinjau, saya mendapatkan satu baris dengan "rm". Ketika saya menjalankan perintah yang sebenarnya, saya mendapatkan pesan kesalahan tentang argumen yang hilang untuk rm. Apakah saya memerlukan sintaks khusus untuk menggunakan hasil dari ls | egrep dalam input xargs?
Nathan
@ Nathan Anda harus melakukan cd ke direktori Anda terlebih dahulu. Tidak ada sintaksis khusus. lsmenyediakan nama file direktori, egrep -vf filelistfilter 50 nama file Anda. Saya khawatir Anda menghapus semua file Anda.
Emmanuel
@ Emueluel Saya menjalankan perintah dari direktori yang berisi file yang akan dihapus.
Nathan
@ Nathan, apakah semua file Anda dihapus?
Emmanuel
tidak, mereka masih di sana.
Nathan
1

Pra-bangun argumen untuk find:

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

Gunakan echobagian untuk melihat apa yang akan dibangun. Hapus echobagian untuk benar-benar menjalankannya.

Pembaruan: Demonstrasi:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"
kojiro
sumber
Saya suka yang terbaik ini karena menghapus kebutuhan kedepan filelist
eyoung100
+1 dari saya, meskipun tidak terlalu baik dengan spasi. Mungkin beberapa tanda kutip tunggal ( ') harus ditambahkan yaitu keep=( -name \'"$REPLY"\' )dan keep+=( -o -name \'"$REPLY"\' ).
Cristian Ciupitu
di atas berbahaya, karena Anda dapat menghapus file secara tidak sengaja.
davidva
@CristianCiupitu bukan? Saya menambahkan demo yang menunjukkan bahwa itu sangat baik berhubungan dengan spasi.
kojiro
@davidva Dalam kondisi apa? Setiap kali Anda mengotomatiskan menghapus hal-hal yang Anda berisiko membuat kesalahan, tetapi dalam parameter pertanyaan saya pikir demo saya membuktikan pendekatan ini masuk akal.
kojiro
1

Dengan zsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Bunyinya baris filelistdalam array dan kemudian menggunakan glob qualifiers / estring untuk glob / pilih hanya nama file yang tidak ada dalam array: .memilih hanya file biasa (tambahkan Djika daftar Anda berisi dotfile) dan negated ^e_'expression'_selanjutnya memilih hanya untuk dimana ekspresi mengembalikan false, yaitu jika nama mereka ( $REPLY) bukan merupakan elemen dari array .
Jika Anda puas dengan hasil ganti print -rldengan rmuntuk benar-benar menghapus file:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Untuk memilih & menghapus file secara rekursif, gunakan */**glob dengan ${REPLY:t}pengubah glob:

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)
don_crissti
sumber
0

Jika Anda memasukkan konten direktori ke dalam file seperti ini:

cd <somedirectory>
ls >> filelist

Buka daftar file dengan editor teks, dan hapus semua file kecuali yang ingin ANDA HAPUS . Itu berani karena itu pendekatan yang berlawanan dengan jawaban di atas

Coba ini:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

Jika Anda melihat daftar file yang di-output dengan layar ganti echo rm -v, seperti:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist
eyoung100
sumber
0

Jalankan skrip di bawah ini.

  1. Awalnya saya menemukan semua file yang ada di dalam direktori dan menyimpan output ke file lain all_files.
  2. Kami memiliki file yang memiliki daftar file yang TIDAK boleh dihapus ( not_to_be_deleted_files).
  3. Saya menambahkan nama file not_to_be_deleted_filesdan files_to_be_deletedke akhir not_to_be_deleted_fileskarena kami membutuhkan 2 file ini.
  4. Sekarang, saya menemukan file yang perlu dihapus menggunakan joinperintah linux dan mengarahkan output ke files_to_be_deleted file.
  5. Sekarang, di loop sementara terakhir saya membaca semua nama file files_to_be_deleteddan menghapus file yang disebutkan dalam nama file itu.

Scriptnya seperti di bawah ini.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

PS : Mungkin, jika Anda ingin ini disimpan sebagai skrip dan menjalankannya, Anda dapat menambahkan nama skrip juga menggunakan echo scriptname >> not_to_be_deleted_files.

Meskipun tidak diperlukan, saya lebih suka melakukannya karena tidak akan ada penyesalan nanti. Saya menguji satu set kecil file dan itu berhasil di sistem saya. Namun, jika Anda ingin memastikan, coba di testdirektori terlebih dahulu dan kemudian hapus file di direktori asli.

Ramesh
sumber
0
  • Gunakan daftar sebagai sumber, untuk memindahkan semua file dalam daftar ke direktori penyimpanan yang baru, kosong, dan kosong.
  • Bandingkan jumlah file dalam daftar dan jumlah file yang disimpan.
  • Jika keduanya cocok, hapus semua file yang belum disimpan dengan metode favorit Anda.
  • Pindahkan file yang disimpan kembali.
Pengguna tidak diketahui
sumber
0

Saya menggunakan pendekatan yang lebih aman dan lebih cepat karena saya memiliki 18.000 file dalam daftar! Saya perlu membersihkan gambar di instalasi Drupal besar.

Menghapus semua file yang tidak ada dalam daftar sama dengan hanya menyimpan file-file yang ada dalam daftar. Jadi saya memutuskan untuk benar-benar menyalin file dari daftar ke lokasi lain, tetapi menyalin 20 GB file akan memakan terlalu banyak ruang dan sangat lambat juga. Jadi triknya adalah menyalin file sebagai hardlinksgantinya, menggunakan -lopsi cp. Ini hampir tidak memakan ruang dan sangat cepat. Selain itu, karena saya perlu mempertahankan struktur direktori, saya menggunakan --parentsopsi.

Berikut ini kutipan dari daftar file saya:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

Jadi contoh barisnya adalah, dengan temp menjadi tujuan:

cp -l --parents 'misc/feed.png' temp

Ini akan membuat struktur ini:

temp
  misc
    feed.png

Perhatikan bahwa destinaton harus dalam sistem file yang sama dengan sumber agar hardlink berfungsi.

Langkah selanjutnya adalah membuat skrip:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

Sekarang, anggap Anda sudah membuat dir kosong / some / where / temp, Anda dapat menyalin file seperti ini:

sh newfilelist 2> missing_files

Perhatikan bagaimana kesalahan berakhir missing_files. Bonus tambahan dari pendekatan ini adalah Anda akan mendapatkan daftar file dari daftar asli yang sebenarnya tidak ada!

Setelah menjalankan skrip, temp hanya akan berisi file-file yang ada di daftar file, tetapi tanpa menghapus apa pun dan tanpa mengambil ruang tambahan. Jika Anda puas dengan hasilnya, Anda dapat menghapus semua file asli termasuk subfolder.

Akhirnya, pindahkan file dan folder dari temp kembali ke lokasi asli.

Untuk 18.000 file hanya butuh beberapa detik.

pelaut
sumber
0

Aman, sederhana.

cd ke direktori.

Buat direktori temp.

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

selesai

paradisaeidae
sumber
Selamat datang di situs ini. Sementara pendekatan Anda akan bekerja jika nama-nama dalam daftar yang disebutkan oleh OP adalah hasil dari pencocokan pola sederhana - yang mungkin merupakan kasusnya - harap dicatat bahwa OP menyatakan bahwa nama file yang dikecualikan disimpan dalam file tertentu; Anda mungkin ingin memperluas jawaban untuk membaca pola pengecualian dari file itu alih-alih mengandalkan satu pola statis, atau harus mengetik-salin beberapa pola yang berpotensi ke konsol.
AdminBee