11

私はシェルスクリプトを初めて使用します。私の疑いがばかげている場合は、ご容赦ください。

2つの異なるディレクトリにpng画像があり、各ディレクトリから画像を取得して処理して新しい画像を生成する実行可能ファイルがあります。

2 つの変数を同時に取ることができる for ループ コンストラクトを探しています。コードは明らかに間違っています。

#!/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

ありがとう!

4

8 に答える 8

18

ロケールの並べ替え順序に基づいて一致する 2 つのディレクトリに依存している場合 (試行のように)、配列が機能するはずです。

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
于 2012-06-26T20:06:30.507 に答える
7

ここでは、長所と短所に関するメモを使用して、探していることを行うためのいくつかの追加の方法を示します.

以下は、改行を含まないファイル名でのみ機能します。ファイルをロックステップでペアリングします。追加のファイル記述子を使用して、最初のリストから読み取ります。さらにファイルim1_dirが含まれている場合、不足するとループが停止im2_dirします。im2_dirさらにファイルが含まれている場合はfile1、すべての不一致に対して空になりますfile2。もちろん、同じ数のファイルが含まれていれば問題ありません。

#!/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<&-

次のようにセミコロンを 2 つのアンパサンドに置き換えることで、どちらのリストが長くても、一致する空でないファイルのみでループが停止するように動作を一貫させることができます。

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

このバージョンでは、forループの代わりにループを使用しwhileます。これは、2 つのリストのうち短い方がなくなると停止します。

#!/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

このバージョンはすぐ上のものと似ていますが、リストの 1 つがなくなると、他のリストがなくなるまでアイテムを再利用するために循環します。それは非常に醜く、同じことを別の方法でもっと簡単に行うことができます。

#!/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

このバージョンは、内側のループ (2 番目のディレクトリ) に配列のみを使用します。最初のディレクトリにあるファイルの数だけ実行されます。

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

for file1 in $im1_dir
do
    run_black "$file1" "${im2_dir[i++]}"
done
于 2012-06-27T01:36:37.927 に答える
4

人里離れた道 (bash) から離れても構わない場合は、Tool Command Language (TCL) に次のようなループ構造があります。

#!/usr/bin/env tclsh

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

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

基本的に、ループは次を読み取ります: list1 から取得した各 item1 および list2 から取得した item2command_nameその後、独自のコマンドに置き換えることができます。

于 2012-06-26T21:03:09.620 に答える
0

これは、同じループで 2 つの変数を使用する別の方法かもしれません。ただし、 iteration の値として使用するには、ディレクトリ内のファイルの総数 (またはループを実行する回数) を知る必要がありますi

ディレクトリ内のファイル数を取得します。

ls /path/*.png | wc -l

ループを実行します。

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

詳細については、このディスカッションを参照してください。

于 2015-10-17T23:13:18.557 に答える
-1

別の解決策。ファイル名を含む 2 つのリストが 1 つに貼り付けられます。

paste <(ls --quote-name ~/prev1/*.png) <(ls --quote-name ~/prev3/*.png) | \
while read args ; do
  run_black $args
done  
于 2012-06-27T10:27:53.447 に答える