2012-06-26 11 views
6

Tôi mới dùng shell scripting. vì vậy vui lòng chịu với tôi nếu nghi ngờ của tôi là quá ngớ ngẩn.bash shell script hai biến trong vòng lặp

Tôi có hình ảnh png trong 2 thư mục khác nhau và tệp thực thi có hình ảnh từ mỗi thư mục và xử lý chúng để tạo hình ảnh mới.

Tôi đang tìm một cấu trúc vòng lặp có thể lấy hai biến cùng một lúc .. điều này là có thể trong C, C++ vv nhưng làm cách nào để thực hiện điều gì đó sau đây. Mã rõ ràng là sai.

#!/bin/sh 

im1_dir=~/prev1/*.png 
im2_dir=~/prev3/*.png 
index=0 

for i,j in $im1_dir $im2_dir # i iterates in im1_dir and j iterates in im2_dir 
do 
    run_black.sh $i $j 
done 

cảm ơn!

+0

Bạn đang tìm kiếm "sản phẩm Descartes"? Ví dụ: nếu thư mục 1 có tệp A B C và thư mục 2 có tệp b c, bạn đang tìm kiếm tệp đầu ra 9 (Aa, Ab, Ac, Ba, Bb, Bc, Ca, Cb, Cc) phải không? – jedwards

+1

@jedwards: Tôi nghĩ OP muốn Aa Bb Cc hơn là một sản phẩm Descartes. –

+0

@ DennisWilliamson: tôi cũng thế, nhưng nghĩ về nó quá nhiều khiến tôi không chắc chắn – jedwards

Trả lời

8

Nếu bạn phụ thuộc vào hai thư mục để phù hợp dựa trên thứ tự được sắp xếp theo ngôn ngữ (như nỗ lực của bạn), thì một mảng sẽ hoạt động.

im1_files=(~/prev1/*.png) 
im2_files=(~/prev3/*.png) 

for ((i=0;i<=${#im1_files[@]};i++)); do 
    run_black.sh "${im1_files[i]}" "${im2_files[i]}" 
done 
+0

Cảm ơn. các hình ảnh trong hai thư mục được sắp xếp có .. điều này có thể làm việc nhưng tôi nhận được một lỗi cú pháp ... "Cú pháp cú pháp:" ("bất ngờ" .... nên các dấu ngoặc tròn ở đó? và không có nó "Cú pháp lỗi: Xấu cho biến vòng lặp " – snowmonkey

+0

Xin lỗi tôi có nghĩa là dấu ngoặc xung quanh ~/prev1/*. Png – snowmonkey

+0

@ user1126374 - Đó là vì/bin/sh của bạn không bị bash. Thay đổi shebang thành #!/Bin/bash – jordanm

3

Nếu bạn không nhớ đi ra khỏi con đường bị đánh đập (bash), Tool Command Language (TCL) có như vậy một cấu trúc vòng lặp:

#!/usr/bin/env tclsh 

set list1 [glob dir1/*] 
set list2 [glob dir2/*] 

foreach item1 $list1 item2 $list2 { 
    exec command_name $item1 $item2 
} 

Về cơ bản, các vòng lặp đọc: cho mỗi mục1 được lấy từ danh sách1 và mục 2 được lấy từ danh sách2. Sau đó, bạn có thể thay thế command_name bằng lệnh của riêng bạn.

+0

bạn có thể sử dụng tclsh chỉ cho một phần của mã trong một tập tin src? Tôi tự hỏi làm thế nào mà sẽ xem xét.... –

3

Dưới đây là một vài cách bổ sung để làm những gì bạn đang tìm kiếm với các ghi chú về ưu và khuyết điểm.

Sau đây chỉ hoạt động với tên tệp không bao gồm dòng mới. Nó ghép nối các tập tin ở chế độ khóa. Nó sử dụng một bộ mô tả tập tin bổ sung để đọc từ danh sách đầu tiên. Nếu im1_dir chứa nhiều tệp hơn, vòng lặp sẽ dừng khi im2_dir hết. Nếu im2_dir chứa nhiều tệp hơn, file1 sẽ trống cho tất cả các số chưa khớp file2. Tất nhiên nếu chúng chứa cùng một số lượng tập tin, không có vấn đề gì.

#!/bin/bash 
im1_dir=(~/prev1/*.png) 
im2_dir=(~/prev3/*.png) 

exec 3< <(printf '%s\n' "${im1_dir[@]}") 

while IFS=$'\n' read -r -u 3 file1; read -r file2 
do 
    run_black "$file1" "$file2" 
done < <(printf '%s\n' "${im1_dir[@]}") 

exec 3<&- 

Bạn có thể thực hiện hành vi phù hợp để các vòng lặp dừng lại chỉ với file phù hợp không có sản phẩm nào không có vấn đề mà danh sách dài bằng cách thay thế các dấu chấm phẩy với một dấu và đôi như vậy:

while IFS=$'\n' read -r -u 3 file1 && read -r file2 

này phiên bản sử dụng vòng lặp for thay vì vòng lặp while. Điều này dừng lại khi ngắn hơn của hai danh sách chạy ra ngoài.

#!/bin/bash 
im1_dir=(~/prev1/*.png) 
im2_dir=(~/prev3/*.png) 

for ((i = 0; i < ${#im1_dir[@]} && i < ${#im2_dir[@]}; i++)) 
do 
    run_black "${im1_dir[i]}" "${im2_dir[i]}" 
done 

Phiên bản này tương tự như phiên bản ở trên, nhưng nếu một trong các danh sách chạy hết, hãy sử dụng lại các mục cho đến khi danh sách còn lại hết. Nó rất xấu và bạn có thể làm điều tương tự một cách đơn giản hơn.

#!/bin/bash 
im1_dir=(~/prev1/*.png) 
im2_dir=(~/prev3/*.png) 

for ((i = 0, j = 0, 
      n1 = ${#im1_dir[@]}, 
      n2 = ${#im2_dir[@]}, 
      s = n1 >= n2 ? n1 : n2, 
      is = 0, js = 0; 

     is < s && js < s; 

     i++, is = i, i %= n1, 
      j++, js = j, j %= n2)) 
do 
    run_black "${im1_dir[i]}" "${im2_dir[i]}" 
done 

Phiên bản này chỉ sử dụng mảng cho vòng lặp bên trong (thư mục thứ hai). Nó sẽ chỉ thực thi nhiều lần vì có các tệp trong thư mục đầu tiên.

#!/bin/bash 
im1_dir=~/prev1/*.png 
im2_dir=(~/prev3/*.png) 

for file1 in $im1_dir 
do 
    run_black "$file1" "${im2_dir[i++]}" 
done 
-1

Một giải pháp khác. Hai danh sách với tên tập tin được dán vào một.

paste <(ls --quote-name ~/prev1/*.png) <(ls --quote-name ~/prev3/*.png) | \ 
while read args ; do 
    run_black $args 
done 
0

Đây có thể là một cách khác để sử dụng hai biến trong cùng một vòng lặp.Nhưng bạn cần biết tổng số tệp (hoặc, số lần bạn muốn chạy vòng lặp) trong thư mục để sử dụng nó làm giá trị của phép lặp i.

Lấy số tập tin trong thư mục:

ls /path/*.png | wc -l 

Bây giờ chạy vòng lặp:

im1_dir=(~/prev1/*.png) 
im2_dir=(~/prev3/*.png) 

for ((i = 0; i < 4; i++)); do run_black.sh ${im1_dir[i]} ${im2_dir[i]}; done 

Để được trợ giúp nhiều hơn xin vui lòng xem discussion này.

0

Rất đơn giản, bạn có thể sử dụng hai hàm vòng lặp trong vấn đề này.

bin bash

index = 0 cho i trong ~/prev1/.png
làm cho j ~/prev3/
.png làm run_black.sh $ i $ j done done

0

Tôi có vấn đề này cho một tình huống tương tự mà tôi muốn một phạm vi trên và dưới cùng một lúc. Đây là giải pháp của tôi; nó không phải là đặc biệt hiệu quả nhưng nó dễ dàng và sạch sẽ và không phải ở tất cả phức tạp với mảng BASH icky và tất cả những điều vô nghĩa.

SEQBOT=$(seq 0 5 $((PEAKTIME-5))) 
SEQTOP=$(seq 5 5 $((PEAKTIME-0))) 

IDXBOT=0 
IDXTOP=0 

for bot in $SEQBOT; do 
    IDXTOP=0 
    for top in $SEQTOP; do 
     if [ "$IDXBOT" -eq "$IDXTOP" ]; then 
      echo $bot $top 
     fi 
     IDXTOP=$((IDXTOP + 1)) 
    done 
    IDXBOT=$((IDXBOT + 1)) 
done