bash shell script two variables in for loop

前端 未结 7 1128
终归单人心
终归单人心 2020-12-09 19:33

I am new to shell scripting. so kindly bear with me if my doubt is too silly.

I have png images in 2 different directories and an executable which takes an images f

相关标签:
7条回答
  • 2020-12-09 20:15

    It is very simple you can use two for loop functions in this problem.

    #bin bash
    index=0
    for i in ~/prev1/*.png  
    do
        for j ~/prev3/*.png
        do 
            run_black.sh $i $j
        done
    done
    
    0 讨论(0)
  • 2020-12-09 20:16

    I have this problem for a similar situation where I want a top and bottom range simultaneously. Here was my solution; it's not particularly efficient but it's easy and clean and not at all complicated with icky BASH arrays and all that nonsense.

    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
    
    0 讨论(0)
  • 2020-12-09 20:17

    This might be another way to use two variables in the same loop. But you need to know the total number of files (or, the number of times you want to run the loop) in the directory to use it as the value of iteration i.

    Get the number of files in the directory:

    ls /path/*.png | wc -l
    

    Now run the loop:

    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
    

    For more help please see this discussion.

    0 讨论(0)
  • 2020-12-09 20:19

    If you don't mind going off the beaten path (bash), the Tool Command Language (TCL) has such a loop construct:

    #!/usr/bin/env tclsh
    
    set list1 [glob dir1/*]
    set list2 [glob dir2/*]
    
    foreach item1 $list1 item2 $list2 {
        exec command_name $item1 $item2
    }
    

    Basically, the loop reads: for each item1 taken from list1, and item2 taken from list2. You can then replace command_name with your own command.

    0 讨论(0)
  • 2020-12-09 20:20

    Here are a few additional ways to do what you're looking for with notes about the pros and cons.

    The following only works with filenames that do not include newlines. It pairs the files in lockstep. It uses an extra file descriptor to read from the first list. If im1_dir contains more files, the loop will stop when im2_dir runs out. If im2_dir contains more files, file1 will be empty for all unmatched file2. Of course if they contain the same number of files, there's no problem.

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

    You can make the behavior consistent so that the loop stops with only non-empty matched files no matter which list is longer by replacing the semicolon with a double ampersand like so:

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

    This version uses a for loop instead of a while loop. This one stops when the shorter of the two lists run out.

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

    This version is similar to the one immediately above, but if one of the lists runs out it wraps around to reuse the items until the other one runs out. It's very ugly and you could do the same thing another way more simply.

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

    This version only uses an array for the inner loop (second directory). It will only execute as many times as there are files in the first directory.

    #!/bin/bash
    im1_dir=~/prev1/*.png
    im2_dir=(~/prev3/*.png)
    
    for file1 in $im1_dir
    do
        run_black "$file1" "${im2_dir[i++]}"
    done
    
    0 讨论(0)
  • 2020-12-09 20:23

    Another solution. The two lists with filenames are pasted into one.

    paste <(ls --quote-name ~/prev1/*.png) <(ls --quote-name ~/prev3/*.png) | \
    while read args ; do
      run_black $args
    done  
    
    0 讨论(0)
提交回复
热议问题