Réponses:
Ce qui suit le fera si, comme je suppose par votre utilisation de ./a.out
, vous êtes sur une plate-forme de type UNIX.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Testez comme suit:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
produit:
1
2
3
4
Pour des gammes plus importantes, utilisez:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Cela produit 1 à 10 inclus, changez simplement la while
condition de terminaison de 10 à 1000 pour une plage beaucoup plus grande comme indiqué dans votre commentaire.
Les boucles imbriquées peuvent se faire ainsi:
target:
num1=1 ; while [[ $$num1 -le 4 ]] ; do \
num2=1 ; while [[ $$num2 -le 3 ]] ; do \
echo $$num1 $$num2 ; \
((num2 = num2 + 1)) ; \
done ; \
((num1 = num1 + 1)) ; \
done
produisant:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
4 1
4 2
4 3
seq
commande qui génère une séquence de nombres existe sur la plupart (tous?) Des systèmes Unix, vous pouvez donc écrire for number in ``seq 1 1000``; do echo $$number; done
(Mettez un seul backtick de chaque côté de la commande seq, pas deux, je ne sais pas comment formater cela correctement en utilisant la syntaxe de stackoverflow)
make
chaque ligne est normalement traitée comme une chose à exécuter dans un sous-shell séparé . Sans suite, il essaierait d'exécuter un sous-shell avec juste (par exemple) for number in 1 2 3 4 ; do
, sans le reste de la boucle. Avec lui, il devient effectivement une seule ligne du formulaire while something ; do something ; done
, qui est une déclaration complète. La $$
question est répondue ici: stackoverflow.com/questions/26564825/… , avec le code apparemment extrait de cette même réponse :-)
Si vous utilisez GNU make, vous pouvez essayer
CHIFFRES = 1 2 3 4 fais le: $ (foreach var, $ (NUMBERS),. / a.out $ (var);)
qui va générer et exécuter
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;
./a.out 1
. ./a.out 2
sera exécuté malgré tout.
LA principale raison d'utiliser make IMHO est le -j
drapeau. make -j5
exécutera 5 commandes shell à la fois. C'est bien si vous avez 4 processeurs, et un bon test de n'importe quel makefile.
Fondamentalement, vous voulez faire voir quelque chose comme:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
C'est -j
sympa (bon signe). Pouvez-vous repérer la plaque de chaudière? On pourrait écrire:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
pour le même effet (oui, c'est la même que la formulation précédente en ce qui concerne make , juste un peu plus compact).
Un peu de paramétrage pour que vous puissiez spécifier une limite sur la ligne de commande (fastidieux car make
n'a pas de bonnes macros arithmétiques, donc je vais tricher ici et utiliser $(shell ...)
)
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
Vous exécutez cela avec make -j5 LAST=550
, avec une valeur par LAST
défaut de 1000.
.PHONY: all
, make recherchera un fichier appelé all
. Si un tel fichier existe, make vérifie ensuite l'heure de la dernière modification de ce fichier, et le makefile ne fera certainement pas ce que vous vouliez. La .PHONY
déclaration indique à make que all
c'est une cible symbolique. Make considérera donc leall
cible est toujours dépassée. Parfait. Voir le manuel.
%
à la règle est disponible comme $*
dans la recette.
Je me rends compte que la question est vieille de plusieurs années, mais ce message peut toujours être utile à quelqu'un car il démontre une approche qui diffère de ce qui précède, et ne dépend ni des opérations du shell ni de la nécessité pour le développeur de supprimer un code dur codé chaîne de valeurs numériques.
la macro intégrée $ (eval ....) est votre amie. Ou peut être au moins.
define ITERATE
$(eval ITERATE_COUNT :=)\
$(if $(filter ${1},0),,\
$(call ITERATE_DO,${1},${2})\
)
endef
define ITERATE_DO
$(if $(word ${1}, ${ITERATE_COUNT}),,\
$(eval ITERATE_COUNT+=.)\
$(info ${2} $(words ${ITERATE_COUNT}))\
$(call ITERATE_DO,${1},${2})\
)
endef
default:
$(call ITERATE,5,somecmd)
$(call ITERATE,0,nocmd)
$(info $(call ITERATE,8,someothercmd)
C'est un exemple simpliste. Il ne s'agrandira pas assez pour les grandes valeurs - cela fonctionne, mais comme la chaîne ITERATE_COUNT augmentera de 2 caractères (espace et point) pour chaque itération, à mesure que vous montez par milliers, il faut progressivement plus de temps pour compter les mots. Comme écrit, il ne gère pas l'itération imbriquée (vous auriez besoin d'une fonction d'itération et d'un compteur séparés pour le faire). Ceci est purement gnu make, aucune exigence de shell (bien que évidemment l'OP cherchait à exécuter un programme à chaque fois - ici, j'affiche simplement un message). Le if dans ITERATE est destiné à attraper la valeur 0, car $ (mot ...) se trompera autrement.
Notez que la chaîne croissante pour servir de compteur est utilisée parce que le $ (mots ...) intégré peut fournir un compte arabe, mais cette marque ne prend pas en charge les opérations mathématiques (vous ne pouvez pas affecter 1 + 1 à quelque chose et obtenir 2, sauf si vous invoquez quelque chose à partir du shell pour l'accomplir pour vous, ou si vous utilisez une opération de macro tout aussi compliquée). Cela fonctionne très bien pour un compteur INCRÉMENTAL, mais pas aussi bien pour un compteur DÉCRÉMENTAL.
Je ne l'utilise pas moi-même, mais récemment, j'ai eu besoin d'écrire une fonction récursive pour évaluer les dépendances des bibliothèques à travers un environnement de construction multi-binaire et multi-bibliothèque où vous devez savoir pour apporter D'AUTRES bibliothèques lorsque vous incluez une bibliothèque qui lui-même a d'autres dépendances (dont certaines varient en fonction des paramètres de construction), et j'utilise une méthode $ (eval) et counter similaire à la précédente (dans mon cas, le compteur est utilisé pour nous assurer que nous n'entrons pas dans une infinité boucle, et aussi comme diagnostic pour signaler combien d'itération était nécessaire).
Quelque chose d'autre ne vaut rien, bien que non significatif pour l'OP Q: $ (eval ...) fournit une méthode pour contourner l'horreur interne de make aux références circulaires, ce qui est tout à fait correct à appliquer lorsqu'une variable est un type macro (initialisé avec =), par rapport à une affectation immédiate (initialisée avec: =). Il y a des moments où vous voulez pouvoir utiliser une variable dans sa propre affectation, et $ (eval ...) vous permettra de le faire. La chose importante à considérer ici est qu'au moment où vous exécutez l'eval, la variable est résolue et la partie résolue n'est plus traitée comme une macro. Si vous savez ce que vous faites et que vous essayez d'utiliser une variable sur le RHS d'une affectation à elle-même, c'est généralement ce que vous voulez de toute façon.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Make'ing heureux.
Pour la prise en charge multiplateforme, rendez le séparateur de commandes (pour exécuter plusieurs commandes sur la même ligne) configurable.
Si vous utilisez MinGW sur une plateforme Windows par exemple, le séparateur de commandes est &
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
Cela exécute les commandes concaténées sur une seule ligne:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
Comme mentionné ailleurs, sur une plate-forme * nix, utilisez CMDSEP = ;
.
Ce n'est pas vraiment une pure réponse à la question, mais une façon intelligente de contourner ces problèmes:
au lieu d'écrire un fichier complexe, déléguez simplement le contrôle par exemple à un script bash comme: makefile
foo : bar.cpp baz.h
bash script.sh
et script.sh ressemble à:
for number in 1 2 3 4
do
./a.out $number
done
eval echo \$${$(var)}
; \ echo $$ var1; \ ((NUM = NUM + 1)); \ done all: set_var ici SSA_CORE0_MAINEXEC est une variable d'environnement qui est déjà définie. Je souhaite donc que cette valeur soit évaluée ou imprimée à l'aide de la variable var1. Je l'ai essayé comme indiqué ci-dessus mais ne fonctionne pas. pLease aide.
bash
et donc utiliser les fonctionnalités. La boucle est l'une des caractéristiques pour lesquelles cela peut être démontré.
Vous pouvez utiliser set -e
comme préfixe pour la boucle for. Exemple:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
quittera immédiatement avec un code de sortie <> 0
.
Bien que la boîte à outils de la table GNUmake ait une vraie while
boucle (quoi que cela signifie dans la programmation GNUmake avec ses deux ou trois phases d'exécution), si la chose dont vous avez besoin est une liste itérative, il existe une solution simple avec interval
. Pour le plaisir, nous convertissons également les nombres en hexadécimal:
include gmtt/gmtt.mk
# generate a list of 20 numbers, starting at 3 with an increment of 5
NUMBER_LIST := $(call interval,3,20,5)
# convert the numbers in hexadecimal (0x0 as first operand forces arithmetic result to hex) and strip '0x'
NUMBER_LIST_IN_HEX := $(foreach n,$(NUMBER_LIST),$(call lstrip,$(call add,0x0,$(n)),0x))
# finally create the filenames with a simple patsubst
FILE_LIST := $(patsubst %,./a%.out,$(NUMBER_LIST_IN_HEX))
$(info $(FILE_LIST))
Production:
./a3.out ./a8.out ./ad.out ./a12.out ./a17.out ./a1c.out ./a21.out ./a26.out ./a2b.out ./a30.out ./a35.out ./a3a.out ./a3f.out ./a44.out ./a49.out ./a4e.out ./a53.out ./a58.out ./a5d.out ./a62.out
#I have a bunch of files that follow the naming convention
#soxfile1 soxfile1.o soxfile1.sh soxfile1.ini soxfile1.txt soxfile1.err
#soxfile2 soxfile2.o soxfile2.sh soxfile2.ini soxfile2.txt soxfile2.err
#sox... .... ..... .... .... ....
#in the makefile, only select the soxfile1.. soxfile2... to install dir
#My GNU makefile solution follows:
tgt=/usr/local/bin/ #need to use sudo
tgt2=/backup/myapplication/ #regular backup
install:
for var in $$(ls -f sox* | grep -v '\.' ) ; \
do \
sudo cp -f $$var ${TGT} ; \
cp -f $$var ${TGT2} ; \
done
#The ls command selects all the soxfile* including the *.something
#The grep command rejects names with a dot in it, leaving
#My desired executable files in a list.