Antworten:
Das Folgende wird es tun, wenn Sie sich, wie ich durch Ihre Verwendung von ./a.out
annehme, auf einer UNIX-Plattform befinden.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Test wie folgt:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
produziert:
1
2
3
4
Verwenden Sie für größere Reichweiten:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Dies gibt 1 bis einschließlich 10 aus. Ändern Sie einfach die while
Abschlussbedingung von 10 auf 1000 für einen viel größeren Bereich, wie in Ihrem Kommentar angegeben.
Verschachtelte Schleifen können folgendermaßen ausgeführt werden:
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
Herstellung:
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
Befehl, der eine Folge von Zahlen generiert, auf den meisten (allen?) Unix-Systemen vorhanden ist, sodass Sie schreiben können for number in ``seq 1 1000``; do echo $$number; done
(Setzen Sie einen einzelnen Backtick auf jede Seite des seq-Befehls, nicht auf zwei, ich weiß nicht, wie ich das richtig formatieren soll unter Verwendung der Syntax von stackoverflow)
make
normalerweise jede Zeile als eine Sache behandelt wird, die in einer separaten Unter-Shell ausgeführt werden soll. Ohne Fortsetzung würde es versuchen, eine Subshell mit nur (zum Beispiel) for number in 1 2 3 4 ; do
ohne den Rest der Schleife auszuführen . Damit wird es effektiv zu einer einzelnen Zeile des Formulars while something ; do something ; done
, was eine vollständige Aussage ist. Die $$
Frage wird hier beantwortet: stackoverflow.com/questions/26564825/… , wobei der Code scheinbar aus dieser Antwort extrahiert wurde :-)
Wenn Sie GNU make verwenden, können Sie es versuchen
ZAHLEN = 1 2 3 4 Tu es: $ (foreach var, $ (NUMBERS) ,. / a.out $ (var);)
die generieren und ausführen
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;
./a.out 1
. ./a.out 2
wird trotzdem ausgeführt.
Der Hauptgrund für make IMHO ist die -j
Flagge. make -j5
führt 5 Shell-Befehle gleichzeitig aus. Dies ist gut, wenn Sie 4 CPUs haben und einen guten Test für jedes Makefile.
Grundsätzlich möchten Sie etwas sehen lassen wie:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
Das ist -j
freundlich (ein gutes Zeichen). Kannst du die Kesselplatte erkennen? Wir könnten schreiben:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
für den gleichen Effekt (ja, dies ist das gleiche wie die vorherige Formulierung, was die Marke betrifft, nur ein bisschen kompakter).
Eine weitere Parametrisierung, damit Sie ein Limit in der Befehlszeile festlegen können (mühsam, da make
es keine guten arithmetischen Makros gibt, also werde ich hier schummeln und verwenden $(shell ...)
)
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
Sie führen dies mit aus make -j5 LAST=550
, wobei LAST
standardmäßig 1000 verwendet wird.
.PHONY: all
sucht make nach einer Datei namens all
. Wenn eine solche Datei vorhanden ist, überprüft make die zuletzt geänderte Zeit dieser Datei, und das Makefile wird mit ziemlicher Sicherheit nicht das tun, was Sie beabsichtigt haben. Die .PHONY
Deklaration sagt make, dass dies all
ein symbolisches Ziel ist. Make wird daher das all
Ziel als immer veraltet betrachten. Perfekt. Siehe das Handbuch.
%
der Regel übereinstimmt, wie $*
im Rezept verfügbar ist .
Mir ist klar, dass die Frage mehrere Jahre alt ist, aber dieser Beitrag kann für jemanden von Nutzen sein, da er einen Ansatz zeigt, der sich von den oben genannten unterscheidet und weder von Shell-Operationen noch von der Notwendigkeit abhängt, dass der Entwickler einen fest codierten Ansatz erstellt Zeichenfolge numerischer Werte.
Das in $ (eval ....) eingebaute Makro ist dein Freund. Oder kann es zumindest sein.
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)
Das ist ein vereinfachtes Beispiel. Es wird für große Werte nicht schön skaliert - es funktioniert, aber da die ITERATE_COUNT-Zeichenfolge für jede Iteration um 2 Zeichen (Leerzeichen und Punkt) erhöht wird, dauert das Zählen der Wörter zunehmend länger, wenn Sie zu Tausenden aufsteigen. Wie geschrieben, werden verschachtelte Iterationen nicht verarbeitet (dazu benötigen Sie eine separate Iterationsfunktion und einen Zähler). Dies ist rein gnu make, keine Shell-Anforderung (obwohl das OP offensichtlich jedes Mal ein Programm ausführen wollte - hier zeige ich lediglich eine Nachricht an). Das if in ITERATE soll den Wert 0 abfangen, da sonst $ (word ...) fehlerhaft wird.
Beachten Sie, dass die wachsende Zeichenfolge, die als Zähler dient, verwendet wird, da das eingebaute $ (Wörter ...) eine arabische Zählung liefern kann, aber make ansonsten keine mathematischen Operationen unterstützt (Sie können etwas nicht 1 + 1 zuweisen und 2 erhalten, es sei denn, Sie rufen etwas aus der Shell auf, um es für Sie zu erledigen, oder verwenden eine ebenso komplizierte Makrooperation. Dies funktioniert hervorragend für einen INCREMENTAL-Zähler, jedoch nicht so gut für einen DECREMENT-Zähler.
Ich benutze dies nicht selbst, aber kürzlich musste ich eine rekursive Funktion schreiben, um Bibliotheksabhängigkeiten in einer Umgebung mit mehreren Binärdateien und mehreren Bibliotheken zu bewerten, in der Sie wissen müssen, wie Sie ANDERE Bibliotheken einbinden können, wenn Sie eine Bibliothek hinzufügen, die selbst hat andere Abhängigkeiten (von denen einige abhängig von den Build-Parametern variieren), und ich verwende eine $ (eval) - und Zählermethode ähnlich der oben genannten (in meinem Fall wird der Zähler verwendet, um sicherzustellen, dass wir nicht irgendwie in ein Endlos geraten Schleife und auch als Diagnose, um zu melden, wie viel Iteration erforderlich war).
Etwas anderes, das nichts wert ist, obwohl es für das Q: $ (eval ...) des OP nicht von Bedeutung ist, bietet eine Methode, um die interne Abscheu von make gegenüber Zirkelverweisen zu umgehen. Dies ist alles gut und in Ordnung, wenn eine Variable ein Makrotyp ist (initialisiert mit =) gegen eine sofortige Zuordnung (initialisiert mit: =). Es gibt Zeiten, in denen Sie eine Variable innerhalb ihrer eigenen Zuweisung verwenden möchten, und mit $ (eval ...) können Sie dies tun. Hierbei ist zu beachten, dass zum Zeitpunkt der Ausführung der Auswertung die Variable aufgelöst wird und der aufgelöste Teil nicht mehr als Makro behandelt wird. Wenn Sie wissen, was Sie tun, und Sie versuchen, eine Variable auf der rechten Seite einer Zuweisung für sich selbst zu verwenden, möchten Sie dies im Allgemeinen trotzdem tun.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Happy make'ing.
Konfigurieren Sie für die plattformübergreifende Unterstützung das Befehlstrennzeichen (zum Ausführen mehrerer Befehle in derselben Zeile).
Wenn Sie MinGW beispielsweise auf einer Windows-Plattform verwenden, lautet das Befehlstrennzeichen &
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
Dadurch werden die verketteten Befehle in einer Zeile ausgeführt:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
Wie an anderer Stelle erwähnt, auf einer * nix-Plattform verwenden CMDSEP = ;
.
Dies ist keine reine Antwort auf die Frage, sondern eine intelligente Methode, um solche Probleme zu umgehen:
Anstatt eine komplexe Datei zu schreiben, delegieren Sie die Steuerung einfach an beispielsweise ein Bash-Skript wie: makefile
foo : bar.cpp baz.h
bash script.sh
und script.sh sieht aus wie:
for number in 1 2 3 4
do
./a.out $number
done
eval echo \$${$(var)}
; \ echo $$ var1; \ ((NUM = NUM + 1)); \ done all: set_var here SSA_CORE0_MAINEXEC ist eine Umgebungsvariable, die bereits festgelegt ist. Daher möchte ich, dass dieser Wert mit der Variablen var1 ausgewertet oder gedruckt wird. Ich habe es wie oben gezeigt versucht, aber es funktioniert nicht. Bitte helfen Sie.
bash
und somit die Funktionen verwenden. Die Schleife ist eines der Merkmale, für die dies demonstriert werden kann.
Sie können set -e
als Präfix für die for-Schleife verwenden. Beispiel:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
wird sofort mit einem Exit-Code beendet <> 0
.
Obwohl das GNUmake-Tabellen-Toolkit eine echte while
Schleife hat (was auch immer dies in der GNUmake-Programmierung mit zwei oder drei Ausführungsphasen bedeutet), gibt es eine einfache Lösung mit, wenn eine iterative Liste benötigt wird interval
. Zum Spaß konvertieren wir die Zahlen auch in Hex:
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))
Ausgabe:
./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.