Tạo và di chuyển hình thu nhỏ theo cách đệ quy


7

Tôi muốn một tập lệnh bash thực hiện như sau:

  • Tìm hình ảnh (jpg, jpeg, JPG, JPEG) đệ quy từ thư mục hiện tại trở xuống
  • Tạo hình thu nhỏ với chuyển đổi của fantemagick
  • Di chuyển hình thu nhỏ đến thư mục khác

Kịch bản hiện tại của tôi trông như thế này:

for f in `find . -type f -iname "*.jpg"`
  do
  convert ./"$f" -resize 800x800\> ./"${f%.jpg}_thumb.jpg"
  mv ./"${f%.jpg}_thumb.jpg" /home/user/thumbs/
done

Nó không chuyển đổi tập tin (hoặc thư mục có tất cả nội dung) có khoảng trắng / ký tự đặc biệt. Tôi đã thử với print0nhưng nó không giúp được gì.


Câu trả lời:


6

Bạn có thể sử dụng các tùy chọn nâng cao hơn như -setkết hợp với phần trăm thoát (cụ thể là %ttrích xuất tên tệp mà không có thư mục hoặc phần mở rộng) để thực hiện thay đổi kích thước, đổi tên và di chuyển của mỗi tệp với một lệnh convertgọi duy nhất :

find . -type f -iname \*.jpg -exec convert {} -resize 800x800\> \
-set filename:name '%t' '/home/user/thumbs/%[filename:name]_thumb.jpg' \;

6

Đừng lặp đi lặp lại trên đầu ra của find. Vấn đề bạn đang gặp phải là một hậu quả điển hình của điều đó.

Ví dụ của bạn là một chút khó khăn do đổi tên tập tin. Một cách không hiệu quả nhưng an toàn để thực hiện là với -exectùy chọn findvà bổ sung shcho mỗi tệp, như sau:

find . -type f -iname "*.jpg" -exec sh -c 'echo convert "$1" -resize 800x800\> /home/user/thumbs/"${1%.jpg}_thumb.jpg"' -- {} \;

Nếu bạn không phiền khi sử dụng cùng tên (với .jpghậu tố thay vì _thumb.jpg), thì hình thức đơn giản này sẽ hoạt động và hiệu quả hơn nhiều:

find . -type f -iname "*.jpg" -exec echo convert "{}" -resize 800x800\> /home/user/thumbs/"{}" \;

Tôi đã thêm các echocâu lệnh vào đó để kiểm tra đầu ra trước khi thực hiện các lệnh. Loại bỏ chúng nếu đầu ra có vẻ tốt.


2
@janos, phk và don_crissti: Tôi chỉ chấp nhận câu trả lời từ don, nhưng tôi cũng nêu lên những câu trả lời đang hoạt động. Cảm ơn những người hỗ trợ của bạn, bạn đã có những câu trả lời rất thú vị / mang tính giáo dục cho câu hỏi đầu tiên của tôi trên trang web này :)
LucaTony

2

Trong giải pháp của bạn, tên tệp được phân chia theo mặc định $IFSbao gồm khoảng trắng.

Hãy thử như sau:

while IFS= read -rd '' f; do

    convert ./"$f" -resize 800x800\> ./"${f%.jpg}_thumb.jpg"
    mv ./"${f%.jpg}_thumb.jpg" /home/user/thumbs/

done < <(find . -type f -iname "*.jpg" -print0)

Việc findin các tên tệp được phân tách bằng byte byte ( \0) và sử dụng -d ''bạn đặt dấu phân cách readlà giống nhau.


@don_crissti Có một ý nghĩa thứ hai -formatnhưng tôi đã hiểu nhầm nó. Ngoài ra còn có -setnhưng tôi không nhận được cú pháp của nó: fantemagick.org/Usage/files/#save_escapes Tôi không nghĩ rằng mình sẽ đầu tư thêm thời gian vào việc này.
phk

@don_crissti Tôi sẽ cung cấp cho tất cả các tệp dưới dạng tham số thông qua find […] -exec mogrify […] {} +nhưng rõ ràng đó là một ý tưởng tồi vì một lý do khác: "Tuy nhiên, cả ba hình ảnh [trong ví dụ] đều được đọc vào bộ nhớ, và sau đó được sửa đổi bằng một lệnh. giải pháp cho một số hình ảnh lớn, hoặc số lượng hình ảnh rất lớn, do sự tích cực của việc đạt đến giới hạn bộ nhớ và do đó sẽ bị tráo đổi đĩa (đập). " (từ liên kết được đăng trong bình luận trước của tôi). Có lẽ khả năng của những trường hợp như vậy cũng là smth. đáng nói trong bài viết tổng quan dài của bạn.
phk

@phk Snipped của bạn cũng hoạt động, tuy nhiên tôi không biết câu trả lời nào là tốt hơn / hiệu quả hơn.
LucaTony
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.