Di chuyển các tệp và nhắc nhở người dùng khi có tên trùng lặp:
Như Subv3rsion của và Eric Leschinski của câu trả lời cho thấy, các -newermt
file ngữ Selects sửa đổi gần đây hơn ngày (và thời gian không bắt buộc) quy định như toán hạng của nó. Để tìm tập tin
- bất cứ nơi nào trong
srcdir
(nghĩa là, bao gồm cả thư mục con, thư mục con của họ, v.v.)
- sửa đổi lần cuối vào (ví dụ) tháng 9 năm 2014
- và chuyển chúng đến
destdir
...bạn có thể chạy:
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -i {} destdir/ \;
Trong một -exec
biểu thức, find vượt qua tên tệp được tìm thấy thay cho {}
. ;
biểu thị -exec
rằng lệnh sẽ được chạy và tất cả các đối số của nó đã được cung cấp (trong trường hợp các biểu thức tiếp theo được chuyển qua để tìm sau các -exec
đối số của vị từ cụ thể đó - xem bên dưới để biết ví dụ về điều này). ;
phải được thoát \;
vì nó không được giải thích đặc biệt bởi vỏ. (Nếu không \
, ;
sẽ kết thúc toàn bộ find
lệnh, hoạt động giống như một dòng mới. Mặc dù find
lệnh này không có gì sau -exec
biểu thức này , nhưng không vượt qua được;
đối số vẫn là một lỗi cú pháp.)
Nếu bạn chỉ muốn liệt kê các tệp - điều này được khuyến khích nếu bạn không chắc chắn làm thế nào các email cũ được lưu trữ hoặc những tệp khác có thể có mặt - bỏ qua -exec
và mọi thứ ở bên phải của nó. (Đối với email, thường các email từ các ngày khác nhau được lưu trữ trong cùng một tệp; đối với ai đó trong tình huống được mô tả trong câu hỏi ở đây, tôi khuyên bạn nên điều tra cách chúng được lưu trữ trước khi di chuyển bất kỳ tệp nào.) Nếu bạn muốn in cả tên của họ và di chuyển họ, thêm -print
trước -exec
.
mv -i
nhắc nhở bất cứ lúc nào một tập tin sẽ được ghi đè ở đích, chẳng hạn như sẽ xảy ra nếu:
- một tệp cùng tên tồn tại từ bản sao lưu trước đó, hoặc
- một tệp có cùng tên nhưng từ một thư mục con khác
srcdir
đã được di chuyển trong cùng một find
hoạt động, hoặc
- (ít có khả năng) một tệp cùng tên đã được tạo ở đâu đó trong
srcdir
cùng một find
hoạt động, sau khi bản gốc được di chuyển nhưng không bao lâu sẽ được tìm thấy một khi find
đi qua một thư mục con khác.
Những cách khác để gọi rm
:
Bạn có các tùy chọn khác về cách xử lý tệp có tên trùng lặp.
- Nếu không có
-i
(nghĩa là ), thường sẽ không nhắc phê duyệt, nhưng sẽ làm như vậy nếu tệp đích là chỉ đọc. (mv {} destdir/
mv
mv
đôi khi thậm chí có thể thành công trong việc ghi đè tệp chỉ đọc, chẳng hạn như nếu người dùng đang chạy nó sở hữu tệp.)
- Nếu bạn thậm chí không muốn mức độ tương tác đó và
mv
luôn muốn (cố gắng) ghi đè lên các tệp có tên giống hệt nhau, hãy sử dụngmv -f
.
- Ngược lại, nếu bạn muốn bỏ qua các tệp nguồn khi đã có một tệp đích cùng tên, hãy sử dụng
mv -n
.
mv
chấp nhận -b
và --backup
cờ để tự động đổi tên các tệp có tên giống hệt đã tồn tại ở đích. Theo mặc định ~
được thêm vào để tạo tên sao lưu và nếu một tệp có tên và một tệp có tên sao lưu đã tồn tại ở đích, thì tệp sao lưu sẽ bị ghi đè. Mặc định này có thể được ghi đè bởi các tùy chọn được truyền khi gọi mv
và bởi các biến môi trường. Xem man mv
để biết chi tiết, và ví dụ dưới đây.
Di chuyển các tệp và tạo bản sao lưu trong trường hợp tên trùng lặp:
Để di chuyển tất cả các tệp, sao lưu các tệp có tên trùng lặp bằng ~
hậu tố và sử dụng hậu tố được đánh số khi các tệp đã tồn tại (để tránh ghi đè lên bất cứ thứ gì), hãy chạy:.~n~
.~
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv --backup=existing {} destdir/ \;
Nếu bạn bỏ qua các tệp có tên trùng lặp và muốn biết những tệp nào:
Nếu bạn sử dụng mv -n
và muốn biết tập tin nào không được di chuyển bởi vì có một tập tin khác có cùng tên, cách tốt nhất có lẽ là chạy find
lại lệnh gốc , không có -exec
và mọi thứ ở bên phải của nó. Điều này sẽ in tên của họ.
Nó cũng sẽ in tên của bất kỳ tệp phù hợp nào được tạo kể từ khi bạn chạy find .... -exec ...
lệnh gốc , nhưng đối với ứng dụng này thường sẽ không có ai vì bạn đang tìm kiếm các tệp có thời gian sửa đổi cũ. Bạn có thể cung cấp cho tệp một dấu thời gian sửa đổi cũ hơn so với tuổi thật của nó touch
và với các cơ chế khác, nhưng điều đó dường như không xảy ra trong trường hợp này mà bạn không biết.
Biết ngay lập tức khi các tệp bị bỏ qua do tên trùng lặp:
mv -n
không báo cáo, cũng không trả lại bất kỳ mã thoát đặc biệt nào , khi nó không di chuyển tệp. Vì vậy, nếu bạn muốn được thông báo ngay lập tức về các tệp bị bỏ qua trong khi find
chạy, bạn sẽ phải thực hiện một bước riêng cho việc đó. Một cách là:
find srcdir -type f -newermt 2014-08-31 ! -newermt 2014-09-30 -exec mv -n {} destdir/ \; \
-exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
Một vài cân nhắc kỹ thuật nhỏ có thể xảy ra: Điều này cảnh báo không chính xác nếu mv
không sao chép tệp vì một lý do khác với lý do tồn tại ở đích và thoát báo cáo thành công . Điều đó dường như là không thể, nhưng tôi không chắc là không thể. Nó cũng có khả năng gặp phải tình trạng chủng tộc : nó sẽ cảnh báo khi không có lỗi thực sự, nếu một tệp mới cùng tên được tạo ở cùng một vị trí trong thời gian rất ngắn sau khi tệp cũ được di chuyển và trước khi kiểm tra xem nếu nó đã được gỡ bỏ. (Xem xét ứng dụng, tôi nghi ngờ một trong hai vấn đề sẽ thực sự xảy ra.) Nó có thể được viết lại để kiểm tra đích trước đódi chuyển tệp thay vì sau: điều kiện cuộc đua sẽ liên quan đến các tệp đích mới được tạo thay vì các tệp nguồn. Và trong khi các lỗi và cảnh báo được báo cáo bởi find
hoặc mv
(hoặc [
, mặc dù không nên có) sẽ được ghi thành lỗi tiêu chuẩn , ...skipped (exists in...
cảnh báo của chúng tôi được ghi vào đầu ra tiêu chuẩn . Thông thường cả hai xuất hiện trên thiết bị đầu cuối của bạn, nhưng điều này có thể quan trọng nếu bạn đang viết kịch bản.
Tôi đã chia lệnh đó thành hai dòng để dễ đọc hơn. Nó có thể được chạy theo cách đó hoặc bạn có thể loại bỏ dòng \
và dòng mới (nghĩa là ngắt dòng).
find
Lệnh đó hoạt động như thế nào?
find
các biến vị ngữ có thể là các phép thử (như -type
và -newermt
), được sử dụng cho các giá trị trả về hoặc các hành động (như -print
và -exec
), thường được sử dụng cho các tác dụng phụ của chúng.
Khi không có toán tử (như -a
for và , -o
for hoặc ) được cung cấp giữa các biểu thức, -a
được ngụ ý. find
sử dụng đánh giá ngắn mạch cho và và hay . (tức là ) chỉ đúng nếu các biểu thức p và q đều đúng, vì vậy q không cần phải được đánh giá nếu p sai. Mặc dù chúng ta thường không nghĩ về nó trong các điều khoản này, đây là lý do tại sao các bài kiểm tra phải đúng với các hành động hoặc bài kiểm tra tiếp theo được đánh giá. Ví dụ, giả sử đến một thư mục. Nó đánh giá là sai, vì vậy nó có thể bỏ qua mọi thứ sau đó.p q
p -a q
find
-type f
Giống như các bài kiểm tra, hành động đánh giá là đúng hay sai. Theo cách này, -exec
báo cáo nếu lệnh được thực thi thoát khỏi báo cáo thành công (đúng) hoặc thất bại (sai). Chúng tôi có chuỗi -exec
biểu thức này được kết nối với ẩn và :
-exec mv -n {} destdir/ \; -exec [ -f {} ] \; -exec printf "\`%s' skipped (exists in \`%s')\\n" {} destdir \;
Điều này cố gắng di chuyển tệp và nếu mv
báo cáo thất bại, dừng lại. Chúng tôi không muốn cảnh báo về một tệp bị bỏ qua chính xác nếu một số vấn đề khác là tại sao nó không được di chuyển.
Nhưng nếu nó đã thành công, nó sau đó chạy các [
lệnh . Giống như find
, [
hỗ trợ loại biểu thức riêng của nó được truyền dưới dạng đối số. [ -f {} ]
kiểm tra xem toán hạng sau -f
(được truyền cho nó find
thay thế {}
) tồn tại (và là một tệp thông thường) và trả về giá trị true / thành công hoặc false / fail.
(Trạng thái thoát của nhiều lệnh được diễn giải tốt nhất là biểu thị thành công hay thất bại, nhưng [
trạng thái tồn tại thường được hiểu là tốt nhất là đúng hoặc sai.)
Nếu [
trả về sai, thì tập tin sẽ biến mất, vì vậy nó đã được di chuyển, do đó không cần phải làm gì cả. Nhưng nếu [
trả về sai, tập tin vẫn còn đó. Sau đó find
đánh giá -exec
biểu thức tiếp theo , trong đó in thông điệp cảnh báo.
Đọc thêm