Unix: Cách xóa các tệp được liệt kê trong một tệp


92

Tôi có một tệp văn bản dài với danh sách mặt nạ tệp mà tôi muốn xóa

Thí dụ:

/tmp/aaa.jpg
/var/www1/*
/var/www/qwerty.php

Tôi cần xóa chúng. Đã thử rm `cat 1.txt` và nó cho biết danh sách quá dài.

Đã tìm thấy lệnh này, nhưng khi tôi kiểm tra các thư mục từ danh sách, một số trong số chúng vẫn có tệp xargs rm <1.txtCuộc gọi rm thủ công loại bỏ các tệp khỏi các thư mục như vậy, vì vậy không có vấn đề gì với quyền.


8
Dù đã sáu năm sau: Bạn có chấp nhận một trong những câu trả lời không? Điều này sẽ đánh dấu câu hỏi là đã được giải quyết và cũng giúp ích cho những người dùng khác.
MERose

Câu trả lời:


114

Điều này không hiệu quả lắm, nhưng sẽ hoạt động nếu bạn cần các mẫu hình cầu (như trong / var / www / *)

for f in $(cat 1.txt) ; do 
  rm "$f"
done

Nếu bạn không có bất kỳ mẫu nào và chắc chắn rằng các đường dẫn của bạn trong tệp không chứa khoảng trắng hoặc những thứ kỳ lạ khác, bạn có thể sử dụng xargs như sau:

xargs rm < 1.txt

4
Điều gì sẽ xảy ra với giải pháp đầu tiên (sử dụng CAT) nếu đường dẫn chứa khoảng trắng?
a.dibacco

58

Giả sử rằng danh sách các tệp có trong tệp 1.txt, sau đó thực hiện:

xargs rm -r <1.txt

Các -rtùy chọn nguyên nhân đệ quy vào bất kỳ thư mục có tên trong1.txt .

Nếu bất kỳ tệp nào ở chế độ chỉ đọc, hãy sử dụng -ftùy chọn để buộc xóa:

xargs rm -rf <1.txt

Hãy thận trọng với đầu vào cho bất kỳ công cụ nào thực hiện xóa theo chương trình. Hãy chắc chắn rằng các tập tin có tên trong tập tin đầu vào là thực sự bị xóa. Hãy đặc biệt cẩn thận về những lỗi chính tả có vẻ đơn giản. Ví dụ: nếu bạn nhập khoảng trắng giữa một tệp và hậu tố của nó, nó sẽ có vẻ là hai tên tệp riêng biệt:

file .txt

thực sự là hai tệp riêng biệt: file.txt.

Điều này có vẻ không quá nguy hiểm, nhưng nếu lỗi đánh máy là như thế này:

myoldfiles *

Sau đó, thay vì xóa tất cả các file bắt đầu với myoldfiles, bạn sẽ kết thúc xóa myoldfilestất cả phi dot-file và thư mục trong thư mục hiện hành. Có lẽ không phải những gì bạn muốn.


1
"myoldfiles /" hoặc "/ tmp" thậm chí còn tai hại hơn với -rf. Lưu ý ký tự khoảng trắng bên cạnh dấu "/".
Ray

23

Dùng cái này:

while IFS= read -r file ; do rm -- "$file" ; done < delete.list

Nếu bạn cần mở rộng toàn cầu, bạn có thể bỏ qua phần trích dẫn $file:

IFS=""
while read -r file ; do rm -- $file ; done < delete.list

Nhưng được cảnh báo rằng tên tệp có thể chứa nội dung "có vấn đề" và tôi sẽ sử dụng phiên bản chưa được trích dẫn. Hãy tưởng tượng mẫu này trong tệp

*
*/*
*/*/*

Điều này sẽ xóa khá nhiều từ thư mục hiện tại! Tôi khuyến khích bạn chuẩn bị danh sách xóa theo cách mà các mẫu hình cầu không còn cần thiết nữa, sau đó sử dụng trích dẫn như trong ví dụ đầu tiên của tôi.


3
Đây hiện là câu trả lời duy nhất mà xử lý tất cả /My Dir With Spaces/ /Spaces and globs/*.txt, --file-with-leading-dashesvà như một phần thưởng đó là POSIX và các công trình trên GNU / Linux, MacOS và BSD.
anh chàng khác

17

Bạn có thể sử dụng '\ n' để xác định ký tự dòng mới làm dấu phân cách.

xargs -d '\n' rm < 1.txt

Hãy cẩn thận với -rf vì nó có thể xóa những gì bạn không muốn nếu 1.txt chứa các đường dẫn có dấu cách. Đó là lý do tại sao dấu phân cách dòng mới an toàn hơn một chút.

Trên hệ thống BSD, bạn có thể sử dụng tùy chọn -0 để sử dụng các ký tự dòng mới làm dấu phân cách như sau:

xargs -0 rm < 1.txt

1
Trên OS X, điều này giúp tôixargs: illegal option -- d
waldyrious

Điểm tốt. Có vẻ như không có tùy chọn nào khác ngoài -0OS X.
Ray

2
xargs -I_ rm _cũng hoạt động trong OS X :) xem stackoverflow.com/a/39335402/266309
waldyrious

Nếu sử dụng xargs BSD (nơi không có -d), trước tiên bạn có thể chuyển đổi dòng mới để null:tr '\n' '\0' < 1.txt | xargs -0 rm
OrangeDog

13

Bạn có thể sử dụng một lớp lót này:

cat 1.txt | xargs echo rm | sh

Cái nào mở rộng shell nhưng thực hiện rmsố lần tối thiểu.


Miễn là bất kỳ mở rộng nào không quá dài?
Douglas Leeder

1
Đúng, một khối cầu có thể tạo ra một danh sách đối số quá dài - bạn có thể thêm -n <n>đối số vào xargsđể giảm số lượng đối số được truyền cho mỗi rm, nhưng điều đó vẫn sẽ không bảo vệ bạn khỏi một khối cầu vượt quá giới hạn.
tgdavies

13

xargs -I{} sh -c 'rm {}' < 1.txtnên làm những gì bạn muốn. Hãy cẩn thận với lệnh này vì một mục nhập sai trong tệp đó có thể gây ra nhiều rắc rối.

Câu trả lời này đã được chỉnh sửa sau khi @tdavies chỉ ra rằng bản gốc không thực hiện mở rộng trình bao.


Cảm ơn, nhưng không cần xóa các thư mục, chỉ các tệp
Alexander

2
Các quả cầu sẽ không được mở rộng, vì chúng không bao giờ được 'nhìn thấy' bởi vỏ.
tgdavies

@tdavies wow - bạn nói đúng. Lệnh này (mặc dù xấu hơn một chút) sẽ hoạt động:xargs -I{} sh -c 'rm {}' < 1.txt
Mark Drago

4

Trong trường hợp cụ thể này, do những nguy hiểm được trích dẫn trong các câu trả lời khác, tôi sẽ

  1. Chỉnh sửa trong ví dụ Vim và :%s/\s/\\\0/g, thoát tất cả các ký tự khoảng trắng bằng dấu gạch chéo ngược.

  2. Sau đó :%s/^/rm -rf /, viết trước lệnh. Với việc -rbạn không phải lo lắng về việc có các thư mục được liệt kê sau các tệp chứa trong đó và với -fnó sẽ không bị phàn nàn do thiếu tệp hoặc các mục trùng lặp.

  3. Chạy tất cả các lệnh: $ source 1.txt


Dấu cách không phải là ký tự duy nhất cần thoát, phổ biến trong tên tệp cũng là dấu ngoặc nhọn có thể dẫn đến mở rộng không mong muốn.
emk2203

4

cat 1.txt | xargs rm -f | bash Chạy lệnh sẽ chỉ thực hiện những việc sau đối với tệp.

cat 1.txt | xargs rm -rf | bash Chạy lệnh sẽ thực hiện hành vi đệ quy sau.


2

Chỉ để cung cấp một cách khác, bạn cũng có thể chỉ cần sử dụng lệnh sau

$ cat to_remove
/tmp/file1
/tmp/file2
/tmp/file3
$ rm $( cat to_remove )

1

Đây là một ví dụ lặp lại khác. Cái này cũng chứa 'if-statement' như một ví dụ về việc kiểm tra xem mục nhập có phải là 'tệp' (hoặc 'thư mục' chẳng hạn):

for f in $(cat 1.txt); do if [ -f $f ]; then rm $f; fi; done

0

Ở đây bạn có thể sử dụng bộ thư mục từ deletelist.txt trong khi tránh một số mẫu cũng

foreach f (cat deletelist.txt)
    rm -rf ls | egrep -v "needthisfile|*.cpp|*.h"
end

0

Điều này sẽ cho phép tên tệp có khoảng trắng (ví dụ có thể tái tạo).

# Select files of interest, here, only text files for ex.
find -type f -exec file {} \; > findresult.txt
grep ": ASCII text$" findresult.txt > textfiles.txt
# leave only the path to the file removing suffix and prefix
sed -i -e 's/:.*$//' textfiles.txt
sed -i -e 's/\.\///' textfiles.txt

#write a script that deletes the files in textfiles.txt
IFS_backup=$IFS
IFS=$(echo "\n\b")
for f in $(cat textfiles.txt); 
do 
rm "$f"; 
done
IFS=$IFS_backup

# save script as "some.sh" and run: sh some.sh

0

Trong trường hợp ai đó thích sedvà xóa mà không mở rộng ký tự đại diện :

sed -e "s/^\(.*\)$/rm -f -- \'\1\'/" deletelist.txt | /bin/sh

Nhắc nhở: sử dụng tên đường dẫn tuyệt đối trong tệp hoặc đảm bảo rằng bạn đang ở đúng thư mục.

Và để hoàn thiện, giống nhau với awk:

awk '{printf "rm -f -- '\''%s'\''\n",$1}' deletelist.txt | /bin/sh

Mở rộng ký tự đại diện sẽ hoạt động nếu các dấu ngoặc kép bị xóa, nhưng điều này sẽ nguy hiểm trong trường hợp tên tệp chứa khoảng trắng. Điều này sẽ cần thêm dấu ngoặc kép xung quanh các ký tự đại diện.

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.