сценарий оболочки bash две переменные в цикле for
Я новичок в скриптах оболочки. будь добр, потерпи меня, если мои сомнения слишком глупы.
У меня есть png-изображения в 2 разных каталогах и исполняемый файл, который берет изображения из каждого каталога и обрабатывает их для создания нового изображения.
Я ищу конструкцию цикла for, которая может принимать две переменные одновременно..это возможно в C, C++ и т. д., Но как я могу выполнить что-то из следующего. Очевидно, что код неверен.
#!/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
спасибо!
7 ответов
Если вы зависите от двух каталогов, чтобы соответствовать на основе порядка сортировки локали (например, ваша попытка), то массив должен работать.
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
Если вы не против сойти с проторенного пути (bash), командный язык инструмента (TCL) имеет такую конструкцию цикла:
#!/usr/bin/env tclsh
set list1 [glob dir1/*]
set list2 [glob dir2/*]
foreach item1 $list1 item2 $list2 {
exec command_name $item1 $item2
}
в основном, цикл читает:для каждого item1 взятого из list1, и item2 взятого из list2. Затем вы можете заменить command_name
С вашей собственной командой.
вот несколько дополнительных способов сделать то, что вы ищете с заметками о плюсах и минусах.
далее работает только с именами файлов, которые не содержат строки. Он соединяет файлы в lockstep. Он использует дополнительный файловый дескриптор для чтения из первого списка. Если 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<&-
вы можете сделать поведение согласованным, чтобы цикл останавливался только с непустыми совпадающими файлами независимо от того, какой список длиннее, заменив точку с запятой двойным амперсандом, например:
while IFS=$'\n' read -r -u 3 file1 && read -r file2
эта версия использует for
петли вместо while
петли. Этот останавливается, когда заканчивается более короткий из двух списков.
#!/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
эта версия аналогична приведенной выше, но если один из списков заканчивается он оборачивается, чтобы повторно использовать элементы, пока не закончится другой. Это очень уродливо, и вы могли бы сделать то же самое по-другому, проще.
#!/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
эта версия использует только массив для внутреннего цикла (второй каталог). Он будет выполняться только столько раз, сколько есть файлов в первом каталоге.
#!/bin/bash
im1_dir=~/prev1/*.png
im2_dir=(~/prev3/*.png)
for file1 in $im1_dir
do
run_black "$file1" "${im2_dir[i++]}"
done
это может быть другой способ использовать две переменные в одном цикле. Но вам нужно знать общее количество файлов (или количество раз, когда вы хотите запустить цикл) в каталоге, чтобы использовать его в качестве значения итерации 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
для получения дополнительной помощи см. Это обсуждение.
Это очень просто, вы можете использовать два для функций цикла в этой проблеме.
бин Баш
=0 для я в ~/prev1/.формат PNGделать для J в ~/prev3/.формат PNG делать run_black.sh $i $j сделанный сделал
У меня есть эта проблема для аналогичной ситуации, когда я хочу верхний и нижний диапазон одновременно. Вот мое решение; это не особенно эффективно, но это легко и чисто и совсем не сложно с грязными массивами BASH и всей этой ерундой.
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
другое решение. Два списка с именами файлов вставляются в один.
paste <(ls --quote-name ~/prev1/*.png) <(ls --quote-name ~/prev3/*.png) | \
while read args ; do
run_black $args
done