Risposte:
Quanto segue lo farà se, come suppongo dal tuo uso ./a.out
, sei su una piattaforma di tipo UNIX.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Prova come segue:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
produce:
1
2
3
4
Per gamme più grandi, utilizzare:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Questo produce da 1 a 10 inclusi, basta cambiare la while
condizione di terminazione da 10 a 1000 per un intervallo molto più ampio come indicato nel tuo commento.
I loop nidificati possono essere eseguiti in questo modo:
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
produzione:
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
comando che genera una sequenza di numeri esiste sulla maggior parte (tutti?) Dei sistemi unix, quindi puoi scrivere for number in ``seq 1 1000``; do echo $$number; done
(Metti un singolo backtick su ciascun lato del comando seq, non due, non so come formattarlo correttamente usando la sintassi di StackOverflow)
make
normalmente tratta ogni linea come un oggetto da eseguire in una sotto-shell separata . Senza continuazione, proverebbe a eseguire una subshell con solo (ad esempio) for number in 1 2 3 4 ; do
, senza il resto del ciclo. Con esso, diventa effettivamente una singola riga del modulo while something ; do something ; done
, che è una dichiarazione completa. La $$
risposta è qui: stackoverflow.com/questions/26564825/… , con il codice apparentemente estratto da questa risposta :-)
Se stai usando GNU make, puoi provare
NUMERI = 1 2 3 4 fallo: $ (foreach var, $ (NUMBERS),. / a.out $ (var);)
che genererà ed eseguirà
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;
./a.out 1
. ./a.out 2
sarà eseguito indipendentemente.
Il motivo principale per utilizzare make IMHO è il-j
bandiera. make -j5
eseguirà 5 comandi shell contemporaneamente. Questo è buono se hai 4 CPU, e un buon test di qualsiasi makefile.
Fondamentalmente, vuoi far vedere qualcosa del tipo:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
Questo è -j
amichevole (un buon segno). Riesci a individuare la piastra della caldaia? Potremmo scrivere:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
per lo stesso effetto (sì, questo è lo stesso della formulazione precedente per quanto riguarda make , solo un po 'più compatto).
Un ulteriore bit di parametrizzazione in modo da poter specificare un limite sulla riga di comando (noioso in quanto make
non ha buone macro aritmetiche, quindi trufferò qui e userò $(shell ...)
)
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
Si esegue con make -j5 LAST=550
, con LAST
impostazione predefinita a 1000.
.PHONY: all
, make cercherà un file chiamato all
. Se esiste un file di questo tipo, controlla quindi l'ultima volta che il file è stato modificato e il makefile quasi certamente non farà ciò che intendevi. La .PHONY
dichiarazione dice a make che all
è un obiettivo simbolico. Make considererà quindi l' all
obiettivo di essere sempre obsoleto. Perfetto. Vedi il manuale
%
alla regola è disponibile come $*
nella ricetta.
Mi rendo conto che la domanda ha diversi anni, ma questo post potrebbe ancora essere utile a qualcuno in quanto dimostra un approccio che differisce da quanto sopra, e non fa affidamento né sulle operazioni della shell né sulla necessità per lo sviluppatore di scrivere un hardcoded stringa di valori numerici.
la macro incorporata $ (eval ....) è tua amica. O può essere almeno.
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)
Questo è un esempio semplicistico. Non si ridimensionerà abbastanza per valori grandi: funziona, ma poiché la stringa ITERATE_COUNT aumenterà di 2 caratteri (spazio e punto) per ogni iterazione, man mano che salirai in migliaia, ci vorrà progressivamente più tempo per contare le parole. Come scritto, non gestisce l'iterazione nidificata (per farlo è necessario disporre di una funzione di iterazione e di un contatore separati). Questo è puramente gnu, nessun requisito di shell (anche se ovviamente l'OP stava cercando di eseguire un programma ogni volta - qui, sto semplicemente visualizzando un messaggio). L'if all'interno di ITERATE ha lo scopo di catturare il valore 0, altrimenti $ (parola ...) si sbaglia.
Tieni presente che la stringa crescente da utilizzare come contatore viene utilizzata perché l'integrato $ (parole ...) può fornire un conteggio arabo, ma ciò rende altrimenti non supporta le operazioni matematiche (Non puoi assegnare 1 + 1 a qualcosa e ottenere 2, a meno che tu non stia invocando qualcosa dalla shell per realizzarla per te, o usando un'operazione macro ugualmente contorta). Questo funziona alla grande per un contatore INCREMENTALE, ma non altrettanto per uno DECREMENTO.
Non lo uso da solo, ma di recente ho dovuto scrivere una funzione ricorsiva per valutare le dipendenze delle librerie in un ambiente di compilazione multi-binario e multi-biblioteca in cui è necessario conoscere per portare ALTRE librerie quando si include qualche libreria che stesso ha altre dipendenze (alcune delle quali variano a seconda dei parametri di compilazione), e io uso un metodo $ (eval) e un contatore simile al precedente (nel mio caso, il contatore viene usato per assicurarci che in qualche modo non andiamo in un infinito loop e anche come diagnostica per segnalare quanta iterazione era necessaria).
Qualcos'altro che non vale nulla, anche se non significativo per Q: $ (eval ...) del PO fornisce un metodo per aggirare l'orrore interna di make ai riferimenti circolari, il che va bene e va fatto valere quando una variabile è di tipo macro (intializzata con =), rispetto a un compito immediato (inizializzato con: =). Ci sono volte in cui vuoi essere in grado di utilizzare una variabile all'interno del proprio compito e $ (eval ...) ti consentirà di farlo. La cosa importante da considerare qui è che nel momento in cui si esegue eval, la variabile viene risolta e quella parte che viene risolta non viene più trattata come una macro. Se sai cosa stai facendo e stai cercando di utilizzare una variabile sull'RHS di un compito a se stesso, questo è generalmente ciò che vuoi che accada comunque.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Lieto successo.
Per il supporto multipiattaforma, rendere configurabile il separatore dei comandi (per l'esecuzione di più comandi sulla stessa riga).
Se ad esempio stai usando MinGW su una piattaforma Windows, il comando di separazione è &
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
Questo esegue i comandi concatenati in una riga:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
Come menzionato altrove, su una piattaforma * nix utilizzare CMDSEP = ;
.
Questa non è in realtà una risposta pura alla domanda, ma un modo intelligente per aggirare tali problemi:
invece di scrivere un file complesso, delegare semplicemente il controllo ad esempio a uno script bash come: makefile
foo : bar.cpp baz.h
bash script.sh
e script.sh si presenta come:
for number in 1 2 3 4
do
./a.out $number
done
eval echo \$${$(var)}
; \ echo $$ var1; \ ((NUM = NUM + 1)); \ done all: set_var qui SSA_CORE0_MAINEXEC è una variabile d'ambiente che è già impostata. Quindi voglio che quel valore venga valutato o stampato usando la variabile var1. L'ho provato come mostrato sopra ma non funziona. per favore aiuto.
bash
e quindi utilizzare le funzionalità. Il loop è una delle funzionalità per le quali ciò può essere dimostrato.
È possibile utilizzare set -e
come prefisso per il ciclo for. Esempio:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
uscirà immediatamente con un codice di uscita <> 0
.
Sebbene il toolkit della tabella GNUmake abbia un vero while
ciclo (qualunque cosa ciò significhi nella programmazione GNUmake con le sue due o tre fasi di esecuzione), se la cosa necessaria è un elenco iterativo, esiste una soluzione semplice interval
. Per divertirci, convertiamo anche i numeri in esadecimali:
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))
Produzione:
./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.