Lặp lại trên n tập tin?


8

Tôi đã có một cái gì đó khá đơn giản tôi muốn làm. Tôi muốn sử dụng montagetrên một thư mục chứa hàng ngàn hình ảnh, với rất ít tùy chọn, cụ thể là:

me@home$ montage -size 256x256 DSC01*.JPG.svg output.png

... nhưng điều đó không đủ tốt, vì nó chỉ chụp được khoảng 100 hình ảnh cùng một lúc; cũng không là

me@home$ montage -size 256x256 *.svg output.png

... Lấy tất cả các hình ảnh cùng một lúc, vì tệp kết quả quá lớn để phân tích cú pháp.

Những gì tôi muốn làm là lặp đi lặp lại một cái gì đó như 100-200 tệp cùng một lúc. Tôi đoán điều này có thể được thực hiện bằng cách sử dụng vòng lặp for (?), Nhưng tôi chỉ hơi bối rối về cách thực hiện điều đó. Tôi đoán có lẽ có một cách thông minh để sử dụng find -exechoặc xargstôi không nghĩ đến. Tôi đang sử dụng bash, nhưng tôi zshthỉnh thoảng sử dụng .

Vì vậy, để kết luận, tôi đang tìm kiếm một lớp lót, với 2600 tệp hình ảnh, gọi điện thoại khoảng 13 hoặc 26 lần (một lần cho mỗi 100-200 tệp) và được cung cấp n tệp, có thể được gọi là bội số của n lần .


1
Các tập tin của bạn có được đặt tên DSC0100.JPG.svg... DSC2600.JPG.svg?
jw013

Câu trả lời:


6

Một bashphương thức, sử dụng các tính năng mảng đặc biệt; có thể dịch zshvới một số sửa đổi:

image_files=(*.svg) # use your own glob expression
n=200               # number of files per command line; adjust to taste
for ((i=0; i < ${#image_files[@]}; i+=n)); do
        montage -size 256x256 "${image_files[@]:i:n}" output-"$i".png
done

1
tôi thấy một chút kịch bản bash này cũng rất mở rộng. tôi chỉ sử dụng nó để di chuyển một số tệp xung quanh (16 tệp cho mỗi thư mục) và nó đã hoạt động trong lần thử đầu tiên, điều này hơi bất ngờ. cảm ơn bạn.
ixtmixilix

5

Bạn có thể sử dụng xargs cho điều đó; thật không may, không thể kết hợp -I (để đưa vào giữa dòng lệnh) và -L (để giới hạn số lượng tệp cho một cuộc gọi đến thực thi). Do đó, tôi đã tạo dòng lệnh này làm ví dụ (nhưng hãy cẩn thận với các ký tự đặc biệt trong tên tệp, chúng không được hỗ trợ):

 ls . | \
   xargs -n 100 echo | \
   (a=1; 
    while read args; do 
     echo montage -size 256x256 $args output-$a.png;
     a=$((a+1)); 
    done
   )

Hủy bỏ echonếu bạn muốn thực sự thực hiện lệnh.

Hãy cẩn thận:

  • tên tệp không được chứa dấu cách hoặc ký tự đặc biệt khác
  • dòng dựng phim cuối cùng có thể có ít hơn 100 tệp trong đó

Cập nhật:

Đây là vòng lặp tương ứng, mà (tôi hy vọng) sẽ giải quyết vấn đề với khoảng trắng trong tên tệp:

a=0
b=0
lst=
for f in *; do 
  a=$((a+1))
  lst="$lst '$f'"
  if test $a -ge 100; then 
    eval echo montage --args $lst target-$b.png
    b=$((b+1))
    a=0
    lst=
  fi 
done

Cập nhật 2: Một giải pháp python, miễn dịch với các ký tự đặc biệt trong tên tệp

#!/usr/bin/env python
# iterate.py

"""Usage: 
%prog <number per call> <file pattern> <command prefix> -- <command postfix>
e.g.  %prog 100 "DSC01*.jpg.svg" montage -size 256x256 -- output-%i.png """

import sys,subprocess,glob,os

if len(sys.argv) < 5: 
  print __doc__.replace("%prog", os.path.basename(sys.argv[0]))
  sys.exit(1)

def chunks(l, n): 
  for i in xrange(0, len(l), n): yield l[i:i+n]

num, pattern, args = int(sys.argv[1]), sys.argv[2], sys.argv[3:]
files, idx = glob.glob(pattern), args.index("--")
before, after = args[0:idx], args[idx+1:]

for idx,chunk in enumerate(chunks(files,num)):
  subprocess.call( before + chunk + [s.replace("%i",str(idx)) for s in after] )

2
Nếu bạn định khuyên bạn nên sử dụng lstrong một đường ống để phân tích đầu ra của nó, bạn cũng nên cảnh báo về nhiều nguy hiểm khi làm việc đó một cách nổi bật và ngay từ đầu để đảm bảo mọi người nhìn thấy nó.
jw013

@ jw013 +1 Có, đó chắc chắn là một mối quan tâm. Tuy nhiên, bài đăng của anh ấy cho tôi biết rằng anh ấy đang sử dụng ảnh được nhập trực tiếp từ máy ảnh kỹ thuật số, không chứa bất kỳ ký tự đặc biệt nào. Làm thế nào bạn sẽ đề nghị để giải quyết vấn đề đó?
daniel kullmann

Có, có vẻ như tên tệp tương đối lành tính (do đó không có downvote). Tuy nhiên, OP đã không thực sự chỉ định những gì họ trông giống như ngoài *.svg(đó là lý do tại sao tôi đăng một bình luận về câu hỏi này). Trong trường hợp chung nhất khi bạn cần xử lý tất cả các tên tệp, bạn sẽ phải sử dụng đến toàn cầu và mảng hoặc find -print0 | xargs -0cấu trúc. Xem câu trả lời của tôi cho một ví dụ về trước đây.
jw013

@ jw013 Câu trả lời của bạn rất hay! Tôi không bao giờ nỗ lực để tìm hiểu làm thế nào mảng hoạt động trong bash. Có lẽ tôi nên.
daniel kullmann

2

Đây là phiên bản sử dụng xargs an toàn cho mọi tên tệp, nhưng yêu cầu tệp tạm thời để lưu trữ số đếm. Điều chỉnh '-n 100' để điều chỉnh số lượng tệp trên mỗi lần dựng phim. Bạn cũng có thể hoán đổi "printf" bằng "find -print0", nhưng đảm bảo rằng nó không tìm thấy "Count.temp".

echo 1 >count.temp
printf "%s\0" *.svg | xargs -0 -n 100 sh -c '
    a=`cat count.temp`
    montage --blah "$@" output-"$a".png
    let a=a+1
    echo "$a" >count.temp
    '
rm count.temp

2

Với GNU Parallel bạn có thể làm:

parallel -N200 montage -size 256x256 {} output{#}.png ::: *.svg

Tất nhiên là an toàn cho các tệp có ký tự đặc biệt (như bạn thường có thể mong đợi về GNU Parallel).

Cài đặt tối thiểu

Nếu bạn chỉ cần song song và chưa cài đặt 'make' (có thể hệ thống đã cũ hoặc Microsoft Windows):

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
mv parallel sem dir-in-your-$PATH/bin/

Xem video giới thiệu để được giới thiệu nhanh: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 hoặc tại http://tinyogg.com/watch/TORaR/http://tinyogg.com/watch/hfxKj /

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.