Je suis nouveau dans les scripts Shell. si gentiment supporter avec moi si mon doute est trop bête.
J'ai des images png dans 2 répertoires différents et un exécutable qui prend une image de chaque répertoire et les traite pour générer une nouvelle image.
Je suis à la recherche d'une construction de boucle for pouvant prendre deux variables simultanément. Ceci est possible en C, C++, etc. Le code est évidemment faux.
#!/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
merci!
Si vous comptez sur les deux répertoires à mettre en correspondance en fonction d'un ordre de tri des paramètres régionaux (comme votre tentative), un tableau devrait alors fonctionner.
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
Voici quelques moyens supplémentaires de faire ce que vous cherchez avec des notes sur les avantages et les inconvénients.
Ce qui suit ne fonctionne qu'avec les noms de fichiers qui n'incluent pas de nouvelles lignes. Il associe les fichiers en un rien de temps. Il utilise un descripteur de fichier supplémentaire pour lire à partir de la première liste. Si im1_dir
contient plus de fichiers, la boucle s'arrêtera lorsque im2_dir
sera épuisé. Si im2_dir
contient plus de fichiers, file1
sera vide pour tous les file2
sans correspondance. Bien sûr, s'ils contiennent le même nombre de fichiers, il n'y a pas de problème.
#!/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<&-
Vous pouvez rendre le comportement cohérent afin que la boucle s'arrête avec uniquement les fichiers correspondants non vides, quelle que soit la liste la plus longue, en remplaçant le point-virgule par un double et commercial, comme suit:
while IFS=$'\n' read -r -u 3 file1 && read -r file2
Cette version utilise une boucle for
au lieu d'une boucle while
. Celui-ci s'arrête lorsque la plus courte des deux listes s'épuise.
#!/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
Cette version est similaire à celle ci-dessus, mais si l'une des listes est épuisée, elle est renvoyée pour permettre de réutiliser les éléments jusqu'à ce que l'autre soit épuisée. C'est très moche et vous pourriez faire la même chose d'une autre manière plus simplement.
#!/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
Cette version utilise uniquement un tableau pour la boucle interne (deuxième répertoire). Il ne s'exécutera autant de fois qu'il y a de fichiers dans le premier répertoire.
#!/bin/bash
im1_dir=~/prev1/*.png
im2_dir=(~/prev3/*.png)
for file1 in $im1_dir
do
run_black "$file1" "${im2_dir[i++]}"
done
Si cela ne vous dérange pas de sortir des sentiers battus (bash), le langage de commande d'outils (TCL) possède une telle construction de boucle:
#!/usr/bin/env tclsh
set list1 [glob dir1/*]
set list2 [glob dir2/*]
foreach item1 $list1 item2 $list2 {
exec command_name $item1 $item2
}
Fondamentalement, la boucle se lit comme suit: pour chaque élément1 extrait de liste1 et élément2 extrait de liste2 . Vous pouvez alors remplacer command_name
par votre propre commande.
C'est très simple, vous pouvez utiliser deux fonctions de boucle for dans ce problème.
#bin bash
index=0
for i in ~/prev1/*.png
do
for j ~/prev3/*.png
do
run_black.sh $i $j
done
done
Cela pourrait être un autre moyen d'utiliser deux variables dans la même boucle. Mais vous devez connaître le nombre total de fichiers (ou le nombre de fois que vous souhaitez exécuter la boucle) dans le répertoire pour pouvoir l'utiliser comme valeur de l'itération i
.
Obtenir le nombre de fichiers dans le répertoire:
ls /path/*.png | wc -l
Maintenant, lancez la boucle:
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
Pour plus d'aide s'il vous plaît voir cette discussion .
J'ai ce problème pour une situation similaire où je veux un haut et un bas en même temps. Voici ma solution. ce n'est pas particulièrement efficace mais c'est facile et propre et pas du tout compliqué avec les tableaux noires de BASH et tout ce non-sens.
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