Odpowiedzi:
Poniższe czynności zrobią to, jeśli, jak zakładam, korzystasz z ./a.out
platformy typu UNIX.
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
Testuj w następujący sposób:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
produkuje:
1
2
3
4
W przypadku większych zakresów użyj:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
Daje to od 1 do 10 włącznie, wystarczy zmienić while
warunek zakończenia z 10 na 1000 dla znacznie większego zakresu, jak wskazano w komentarzu.
Zagnieżdżone pętle można wykonać w następujący sposób:
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
produkujący:
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
polecenie generujące sekwencję liczb istnieje w większości (wszystkich?) Systemach unixowych, więc możesz pisaćfor number in ``seq 1 1000``; do echo $$number; done
(Umieść pojedynczy backstick po każdej stronie polecenia seq, a nie dwa, nie wiem jak poprawnie sformatować to przy użyciu składni stackoverflow)
make
normalnie traktuje każdą linię jako rzecz do uruchomienia w osobnej podpowłoce. Bez kontynuacji próbowałby uruchomić podpowłokę za pomocą (na przykład) for number in 1 2 3 4 ; do
, bez reszty pętli. Dzięki temu skutecznie staje się pojedynczą linią formularza while something ; do something ; done
, co jest kompletnym zestawieniem. Odpowiedź na $$
pytanie tutaj: stackoverflow.com/questions/26564825/... , z pozornie wyodrębnionym kodem z tej samej odpowiedzi :-)
Jeśli używasz GNU make, możesz spróbować
LICZBY = 1 2 3 4 Zrób to: $ (foreach var, $ (NUMBERS),. / a.out $ (var);)
które wygenerują i wykonają
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;
./a.out 1
. ./a.out 2
zostanie wykonany niezależnie.
Głównym powodem, aby make IMHO jest-j
flaga.make -j5
uruchomi 5 poleceń powłoki jednocześnie. Jest to dobre, jeśli masz 4 procesory i dobry test dowolnego makefile.
Zasadniczo chcesz, aby zobaczyłeś coś takiego:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
To jest -j
przyjazne (dobry znak). Czy dostrzegasz płytę kotła? Możemy napisać:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
dla tego samego efektu (tak, jest to taki sam, jak poprzedni sformułowanie, o ile marka obawia się, po prostu nieco bardziej zwarty).
Dalszy kawałek parametryzacji, abyś mógł określić limit w wierszu poleceń (żmudne jak make
nie ma żadnych dobrych makr arytmetycznych, więc oszuka tutaj i użyję $(shell ...)
)
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
Uruchamiasz to make -j5 LAST=550
z LAST
domyślną wartością 1000.
.PHONY: all
make wyszuka plik o nazwie all
. Jeśli taki plik istnieje, make sprawdzi następnie czas ostatniej zmiany tego pliku, a makefile prawie na pewno nie zrobi tego, co zamierzałeś. .PHONY
Deklaracja mówi sprawi że all
jest symbolicznym celem. Marka uzna zatem, że all
cel jest zawsze nieaktualny. Idealny. Zobacz instrukcję.
%
do reguły, jest dostępne jak $*
w przepisie.
Zdaję sobie sprawę, że pytanie ma kilka lat, ale ten post może nadal być dla kogoś przydatny, ponieważ pokazuje podejście, które różni się od powyższego i nie jest uzależnione od operacji powłoki ani potrzeby dewelopera wykreślenia na stałe ciąg wartości liczbowych.
wbudowane makro $ (eval ....) jest twoim przyjacielem. Lub może być przynajmniej.
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)
To jest uproszczony przykład. Nie skaluje się ładnie przy dużych wartościach - działa, ale ponieważ łańcuch ITERATE_COUNT zwiększy się o 2 znaki (spacja i kropka) dla każdej iteracji, w miarę zwiększania się do tysięcy, policzenie słów zajmuje coraz więcej czasu. Jak napisano, nie obsługuje zagnieżdżonej iteracji (aby to zrobić, potrzebujesz osobnej funkcji iteracji i licznika). Jest to czysto gnu make, nie wymaga powłoki (chociaż oczywiście OP chciał uruchomić program za każdym razem - tutaj po prostu wyświetlam komunikat). Jeśli w ciągu ITERATE ma przechwycić wartość 0, ponieważ $ (słowo ...) w przeciwnym razie popełni błąd.
Zauważ, że rosnący ciąg znaków, który ma służyć jako licznik, jest wykorzystywany, ponieważ wbudowane $ (słowa ...) może zapewnić liczbę arabską, ale to make nie obsługuje operacji matematycznych (nie możesz przypisać 1 + 1 do czegoś i dostać 2, chyba że wywołujesz coś z powłoki, aby to zrobić, lub używasz równie skomplikowanej operacji makra). Działa to świetnie w przypadku licznika INCREMENTAL, ale nie tak dobrze w przypadku DECREMENT.
Nie używam tego osobiście, ale ostatnio musiałem napisać funkcję rekurencyjną, aby ocenić zależności bibliotek w wielo-binarnym, wielobibliotkowym środowisku kompilacji, w którym musisz wiedzieć, aby wprowadzić INNE biblioteki, jeśli dodasz bibliotekę, która sam ma inne zależności (niektóre z nich różnią się w zależności od parametrów kompilacji), a ja używam metody $ (eval) i counter podobnej do powyższej (w moim przypadku licznik jest używany, aby upewnić się, że nie przejdziemy w nieskończoność pętli, a także jako narzędzie diagnostyczne do zgłaszania, ile iteracji było konieczne).
Coś innego nic nie warte, choć nieistotne dla Q OP: $ (eval ...) zapewnia metodę obejścia wewnętrznej wstrętności make do odwołań cyklicznych, co jest dobre i dobre do egzekwowania, gdy zmienna jest typem makra (zainicjalizowana z =), a natychmiastowe przypisanie (zainicjowane za pomocą: =). Są chwile, kiedy chcesz mieć możliwość korzystania ze zmiennej w ramach jej własnego przypisania, a $ (eval ...) pozwoli ci to zrobić. Ważną rzeczą do rozważenia w tym miejscu jest to, że w momencie uruchomienia eval zmienna zostaje rozwiązana, a ta część, która jest rozwiązana, nie jest już traktowana jako makro. Jeśli wiesz, co robisz i próbujesz użyć zmiennej w RHS przypisania do siebie, na ogół i tak chcesz to zrobić.
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
Happy make'ing.
Aby umożliwić obsługę wielu platform, skonfiguruj separator poleceń (do wykonywania wielu poleceń w tym samym wierszu).
Jeśli używasz MinGW na przykład na platformie Windows, separatorem poleceń jest &
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
Spowoduje to wykonanie połączonych poleceń w jednym wierszu:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
Jak wspomniano w innym miejscu, na platformie * nix CMDSEP = ;
.
To nie jest tak naprawdę czysta odpowiedź na pytanie, ale inteligentny sposób na obejście takich problemów:
zamiast pisać złożony plik, po prostu przekaż kontrolę na przykład skryptowi bash, np .: makefile
foo : bar.cpp baz.h
bash script.sh
i script.sh wygląda następująco:
for number in 1 2 3 4
do
./a.out $number
done
eval echo \$${$(var)}
; \ echo $$ var1; \ ((NUM = NUM + 1)); \ done all: set_var tutaj SSA_CORE0_MAINEXEC to zmienna środowiskowa, która jest już ustawiona, więc chcę, aby ta wartość została oszacowana lub wydrukowana za pomocą zmiennej var1. Próbowałem, jak pokazano powyżej, ale nie działa. proszę pomóż.
bash
i tym samym korzystać z tych funkcji. Pętla jest jedną z cech, dla których można to wykazać.
Możesz użyć set -e
jako prefiksu dla pętli for. Przykład:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
natychmiast wyjdzie z kodem wyjścia <> 0
.
Chociaż zestaw narzędzi tabeli GNUmake ma prawdziwą while
pętlę (cokolwiek to oznacza w programowaniu GNUmake z jego dwoma lub trzema fazami wykonania), jeśli potrzebna jest lista iteracyjna, istnieje proste rozwiązanie interval
. Dla zabawy zmieniamy też liczby na szesnastkowe:
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))
Wynik:
./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.