Xóa tất cả các tệp trong một thư mục có tên không khớp với một dòng trong danh sách tệp


9

Tôi có một thư mục với hơn 1000 tập tin. Trong một tệp văn bản, tôi có khoảng 50 tên tệp, mỗi tên một dòng. Tôi muốn xóa tất cả các tệp trong thư mục có tên tệp không tương ứng với một mục trong danh sách. Cách tốt nhất để làm điều này là gì? Tôi đã bắt đầu một tập lệnh shell, nhưng không thể xác định lệnh thích hợp để xác định trong tên tệp có trong danh sách. Cảm ơn.

Câu trả lời:


8

Tôi nhận ra rằng bất kỳ câu hỏi yêu cầu làm thế nào để xóa các tập tin phải được thực hiện hết sức cẩn thận. Câu trả lời đầu tiên của tôi quá vội vàng Tôi đã không nhận ra một thực tế rằng các filelist có thể không đúng định dạng được sử dụng với egrep. Tôi đã chỉnh sửa câu trả lời để giảm rủi ro đó.

Điều đó sẽ làm việc cho các tệp không có không gian trong tên:

Trước tiên hãy xây dựng lại filelist của bạn để đảm bảo khớp với tên tệp chính xác:

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

xây dựng các lệnh rm

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

Kiểm tra xem tập lệnh rm có phù hợp với bạn không (Bạn có thể thực hiện bằng "vim" hoặc "ít hơn").
Sau đó thực hiện hành động:

sh -x rmscript

Nếu các tệp có khoảng trắng trong tên của chúng (nếu các tệp có "tên thì điều này sẽ không hoạt động):

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

tất nhiên các filelist không nên ở trong cùng một thư mục!

EDITED:

Danh sách tệp của Nathan chứa các tên khớp với tất cả các tệp trong thư mục (như "html" khớp với "bob.html"). Vì vậy, không có gì đã bị xóa vì egrep -vfhấp thụ tất cả các luồng. Tôi đã thêm một lệnh để đặt "^" và "$" xung quanh mỗi tên tệp. Tôi đã may mắn ở đây rằng danh sách tập tin của Nathan là chính xác. Nó sẽ được định dạng DOS với các dòng kết thúc CR-LF hoặc với các khoảng trắng bổ sung, không có tệp nào được lưu giữ bởi egrep và tất cả đã bị xóa.


Khi tôi chạy lệnh xem trước, tôi nhận được một dòng với "rm". Khi tôi chạy lệnh thực tế, tôi nhận được thông báo lỗi về các đối số bị thiếu cho rm. Tôi có cần cú pháp đặc biệt để sử dụng kết quả từ ls | egrep trong đầu vào xargs?
Nathan

@Nathan bạn phải cd vào thư mục của bạn trước. Không có cú pháp đặc biệt. lscung cấp tên tệp thư mục, egrep -vf filelistlọc 50 tên tệp của bạn. Tôi sợ bạn đã xóa tất cả các tập tin của bạn.
Emmanuel

@Emamanuel Tôi đang chạy lệnh từ thư mục chứa các tệp sẽ bị xóa.
Nathan

@Nathan tất cả các tập tin của bạn đã bị xóa?
Emmanuel

không, họ vẫn ở đó
Nathan

1

Xây dựng trước các đối số để 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 {} +

Sử dụng các echobộ phận để xem những gì sẽ được xây dựng. Loại bỏ các echobộ phận để thực sự chạy nó.

Cập nhật: Trình diễn:

##
# 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"

tôi thích cái này nhất vì nó loại bỏ sự cần thiết của người làm phim
eyoung100

+1 từ tôi, mặc dù nó không xử lý tốt với không gian. Có lẽ một số dấu ngoặc đơn ( ') nên được thêm vào tức là keep=( -name \'"$REPLY"\' )keep+=( -o -name \'"$REPLY"\' ).
Cristian Ciupitu

ở trên là nguy hiểm, bởi vì bạn có thể xóa các tập tin vô tình.
davidva

@CristianCiupitu không? Tôi đã thêm một bản demo cho thấy nó xử lý rất tốt với khoảng trắng.
kojiro

@davidva Trong hoàn cảnh nào? Bất cứ khi nào bạn tự động xóa những thứ bạn có nguy cơ mắc lỗi, nhưng trong các thông số của câu hỏi tôi nghĩ bản demo của tôi chứng minh cách tiếp cận này là âm thanh.
kojiro

1

Với zsh:

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

Nó đọc các dòng filelisttrong một mảng và sau đó sử dụng các vòng loại / echuỗi toàn cầu để toàn cầu / chỉ chọn các tên tệp không có trong mảng: .chỉ chọn các tệp thông thường (thêm Dnếu danh sách của bạn chứa dotfiles) và chỉ phủ định ^e_'expression'_chọn thêm các tên cho mà biểu thức trả về false, tức là nếu tên của chúng ( $REPLY) không phải là một phần tử của mảng .
Nếu bạn hài lòng với kết quả thay thế print -rlbằng rmđể thực sự xóa các tệp:

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

Để chọn và xóa các tệp đệ quy, hãy sử dụng toàn */**cầu với công cụ ${REPLY:t}sửa đổi toàn cục :

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

0

Nếu bạn đặt nội dung của thư mục vào một tệp như vậy:

cd <somedirectory>
ls >> filelist

Mở filelist bằng trình soạn thảo văn bản và xóa tất cả các tệp ngoại trừ những tệp bạn muốn XÓA . Điều đó được in đậm bởi vì đó là cách tiếp cận ngược lại với câu trả lời ở trên

Thử cái này:

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

Nếu bạn thấy danh sách các tệp xuất ra màn hình, hãy thay thế echo bằng rm -v, như vậy:

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

0

Chạy đoạn script dưới đây.

  1. Ban đầu tôi đang tìm tất cả các tệp có trong thư mục và lưu trữ đầu ra sang một tệp khác all_files.
  2. Chúng tôi có một tệp có danh sách các tệp KHÔNG nên bị xóa ( not_to_be_deleted_files).
  3. Tôi đang thêm tên tệp not_to_be_deleted_filesfiles_to_be_deletedđến cuối not_to_be_deleted_filesvì chúng ta cần 2 tệp này.
  4. Bây giờ, tôi đang tìm các tập tin cần phải xóa bằng joinlệnh linux và chuyển hướng đầu ra thành files_to_be_deleted tập tin.
  5. Bây giờ, trong vòng lặp while cuối cùng tôi đang đọc tất cả các tên tệp trong files_to_be_deletedvà xóa các tệp được đề cập trong tên tệp đó.

Kịch bản như dưới đây.

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 : Có lẽ, nếu bạn muốn nó được lưu dưới dạng tập lệnh và chạy nó, bạn có thể thêm tên tập lệnh cũng bằng cách sử dụng echo scriptname >> not_to_be_deleted_files.

Mặc dù nó không bắt buộc, tôi thích làm điều đó hơn vì sẽ không hối tiếc về sau. Tôi đã thử nghiệm cho một tập hợp nhỏ các tập tin và nó hoạt động trong hệ thống của tôi. Tuy nhiên, nếu bạn muốn chắc chắn, testtrước tiên hãy thử trong một thư mục và sau đó xóa các tệp trong thư mục gốc.


0
  • Sử dụng danh sách làm nguồn, để di chuyển tất cả các tệp trong danh sách sang một lưu-dir mới, mới và trống.
  • So sánh số lượng tệp trong danh sách và số lượng tệp đã lưu.
  • Nếu cả hai khớp nhau, hãy xóa tất cả các tệp chưa được lưu bằng phương thức yêu thích của bạn.
  • Di chuyển các tập tin đã lưu trở lại.

0

Tôi đã tìm kiếm một cách tiếp cận an toàn hơn và nhanh hơn nhiều vì tôi có 18.000 tệp trong danh sách! Tôi cần phải dọn sạch hình ảnh trong một bản cài đặt Drupal lớn.

Xóa tất cả các tệp không có trong danh sách cũng giống như chỉ giữ lại những tệp có trong danh sách. Vì vậy, tôi quyết định thực sự sao chép các tệp từ danh sách sang một vị trí khác, nhưng sao chép 20 GB tệp sẽ chiếm quá nhiều dung lượng và cũng rất chậm. Vì vậy, mẹo là sao chép các tập tin hardlinksthay vào đó, sử dụng -ltùy chọn cp. Điều này chiếm gần như không có không gian và rất nhanh. Ngoài ra, vì tôi cần bảo toàn cấu trúc thư mục, tôi đã sử dụng --parentstùy chọn này.

Đây là một đoạn trích từ danh sách tập tin của tôi:

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

Vì vậy, một dòng ví dụ sẽ là, với temp là đích:

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

Điều này sẽ tạo ra cấu trúc này:

temp
  misc
    feed.png

Lưu ý rằng Destinaton phải nằm trong cùng hệ thống tệp với nguồn để các liên kết cứng hoạt động.

Bước tiếp theo là xây dựng tập lệnh:

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

Bây giờ, giả sử bạn đã tạo thư mục trống / some / where / temp, bạn có thể sao chép các tệp như thế này:

sh newfilelist 2> missing_files

Lưu ý làm thế nào lỗi kết thúc trong missing_files. Phần thưởng thêm vào của phương pháp này là bạn sẽ nhận được một danh sách các tệp từ danh sách gốc thực sự không tồn tại!

Sau khi chạy tập lệnh, temp sẽ chỉ chứa các tệp trong danh sách tệp, nhưng không xóa bất cứ thứ gì và không chiếm thêm dung lượng. Nếu bạn hài lòng với kết quả, bạn có thể xóa tất cả các tệp gốc bao gồm các thư mục con.

Cuối cùng, di chuyển các tập tin và thư mục từ temp trở lại vị trí ban đầu.

Đối với các tệp 18.000, chỉ mất vài giây.


0

An toàn, đơn giản.

cd vào thư mục.

Tạo một thư mục tạm thời.

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

làm xong.


Chào mừng đến với trang web. Mặc dù cách tiếp cận của bạn sẽ hoạt động nếu các tên trong danh sách được OP đề cập là kết quả của một khớp mẫu đơn giản - rất có thể là trường hợp - xin lưu ý rằng OP tuyên bố rằng tên tệp cần loại trừ được lưu trữ trong một tệp cụ thể; bạn có thể muốn mở rộng câu trả lời của mình để đọc các mẫu loại trừ khỏi tệp đó thay vì dựa vào một mẫu tĩnh hoặc phải sao chép có khả năng sao chép nhiều mẫu vào bảng điều khiển.
AdminBee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.