ฉันต้องการรันคำสั่งต่อไปนี้:
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
วิธีการเขียนสิ่งนี้เป็นวงในMakefile
?
ฉันต้องการรันคำสั่งต่อไปนี้:
./a.out 1
./a.out 2
./a.out 3
./a.out 4
.
.
. and so on
วิธีการเขียนสิ่งนี้เป็นวงในMakefile
?
คำตอบ:
ต่อไปนี้จะทำถ้าอย่างที่ฉันคิดว่าคุณใช้./a.out
คุณอยู่บนแพลตฟอร์มประเภท UNIX
for number in 1 2 3 4 ; do \
./a.out $$number ; \
done
ทดสอบดังนี้:
target:
for number in 1 2 3 4 ; do \
echo $$number ; \
done
ผลิต:
1
2
3
4
สำหรับช่วงที่ใหญ่กว่าให้ใช้:
target:
number=1 ; while [[ $$number -le 10 ]] ; do \
echo $$number ; \
((number = number + 1)) ; \
done
ผลลัพธ์นี้รวม 1 ถึง 10 เพียงแค่เปลี่ยนwhile
เงื่อนไขการยกเลิกจาก 10 เป็น 1,000 สำหรับช่วงที่ใหญ่กว่ามากตามที่ระบุไว้ในความคิดเห็นของคุณ
ลูปซ้อนสามารถทำได้ดังนี้:
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
การผลิต:
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
คำสั่งที่สร้างลำดับของตัวเลขนั้นมีอยู่ในระบบ unix ส่วนใหญ่ (ทั้งหมด?) ดังนั้นคุณสามารถเขียนfor number in ``seq 1 1000``; do echo $$number; done
(ใส่ backtick เดียวที่ด้านข้างของแต่ละคำสั่ง seq ไม่ใช่สองฉันไม่ทราบวิธีการจัดรูปแบบนี้อย่างถูกต้อง ใช้ไวยากรณ์ของ stackoverflow)
make
โดยทั่วไปถือว่าแต่ละบรรทัดเป็นสิ่งที่เรียกใช้ในsub-shell แยก หากไม่มีการต่อเนื่องมันจะพยายามเรียกใช้ subshell ด้วย (ตัวอย่าง) for number in 1 2 3 4 ; do
โดยไม่มีลูปที่เหลือ ด้วยมันจะกลายเป็นบรรทัดเดียวของแบบฟอร์มได้อย่างมีประสิทธิภาพwhile something ; do something ; done
ซึ่งเป็นคำสั่งที่สมบูรณ์ $$
คำถามเป็นคำตอบที่นี่: stackoverflow.com/questions/26564825/...กับรหัสที่สกัดจากดูเหมือนว่าคำตอบนี้มาก :-)
ถ้าคุณใช้ GNU ทำคุณสามารถลอง
NUMBERS = 1 2 3 4 ทำมัน: $ (foreach var, $ (NUMBERS),. / a.out $ (var);)
ซึ่งจะสร้างและดำเนินการ
./a.out 1; ./a.out 2; ./a.out 3; ./a.out 4;
./a.out 1
วิธีการแก้ปัญหานี้จะซ่อนรหัสทางออกของ ./a.out 2
จะถูกดำเนินการโดยไม่คำนึงถึง
เหตุผลสำคัญที่จะทำให้การใช้งาน IMHO เป็น-j
ธง make -j5
จะเรียกใช้ 5 คำสั่งเชลล์ในครั้งเดียว นี่เป็นสิ่งที่ดีถ้าคุณมี 4 ซีพียูพูดและทำการทดสอบที่ดีของไฟล์ใด ๆ
โดยทั่วไปคุณต้องการให้เห็นสิ่งที่ชอบ:
.PHONY: all
all: job1 job2 job3
.PHONY: job1
job1: ; ./a.out 1
.PHONY: job2
job2: ; ./a.out 2
.PHONY: job3
job3: ; ./a.out 3
นี่เป็น-j
มิตร (เป็นสัญญาณที่ดี) คุณสามารถมองเห็นหม้อไอน้ำจานได้หรือไม่? เราสามารถเขียน:
.PHONY: all job1 job2 job3
all: job1 job2 job3
job1 job2 job3: job%:
./a.out $*
สำหรับผลเช่นเดียวกัน (ใช่นี้เป็นเช่นเดียวกับการกำหนดก่อนหน้านี้เท่าที่ทำให้เป็นห่วงเพียงเล็กน้อยขนาดกะทัดรัดมากขึ้น)
การเพิ่มพารามิเตอร์อีกเล็กน้อยเพื่อให้คุณสามารถระบุขีด จำกัด บนบรรทัดคำสั่ง (น่าเบื่อเหมือนmake
ไม่มีแมโครทางคณิตศาสตร์ที่ดีดังนั้นฉันจะโกงที่นี่และใช้$(shell ...)
)
LAST := 1000
NUMBERS := $(shell seq 1 ${LAST})
JOBS := $(addprefix job,${NUMBERS})
.PHONY: all ${JOBS}
all: ${JOBS} ; echo "$@ success"
${JOBS}: job%: ; ./a.out $*
คุณเรียกใช้สิ่งนี้ด้วยmake -j5 LAST=550
โดยมีค่าเริ่มต้นLAST
เป็น 1,000
.PHONY: all
all
หากไฟล์ดังกล่าวมีอยู่ให้ทำการตรวจสอบไฟล์ล่าสุดที่เปลี่ยนแปลงและ makefile นั้นแทบจะไม่ทำสิ่งที่คุณต้องการแน่นอน การ.PHONY
ประกาศบอกว่าall
เป็นเป้าหมายที่เป็นสัญลักษณ์ ทำให้จะพิจารณาall
เป้าหมายที่จะล้าสมัยเสมอ สมบูรณ์ ดูคู่มือ
%
ในกฎที่มีอยู่$*
ในสูตร
ฉันรู้ว่าคำถามมีอายุหลายปี แต่โพสต์นี้อาจยังใช้กับใครบางคนเพราะมันแสดงให้เห็นถึงวิธีการที่แตกต่างจากข้างต้นและไม่พึ่งพาการดำเนินการของเชลล์ทั้งสองและไม่ต้องการให้นักพัฒนาสร้าง schpeel สตริงของค่าตัวเลข
builtin $ built-in มาโครเป็นเพื่อนของคุณ หรืออาจเป็นอย่างน้อย
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)
นั่นเป็นตัวอย่างที่ง่าย จะไม่ปรับขนาดสำหรับค่าขนาดใหญ่ - ใช้งานได้ แต่เนื่องจากสตริง ITERATE_COUNT จะเพิ่มขึ้น 2 ตัวอักษร (ช่องว่างและจุด) สำหรับการวนซ้ำแต่ละครั้งเมื่อคุณได้รับเป็นหลักพันจะใช้เวลานานในการนับคำ ตามที่เขียนไว้มันไม่ได้จัดการการวนซ้ำที่ซ้ำกัน (คุณต้องมีฟังก์ชั่นการแยกซ้ำและตัวนับเพื่อดำเนินการ) นี่คือ gnu ล้วนๆ, ไม่มีข้อกำหนดของเชลล์ (แม้ว่าชัด ๆ ว่า OP ต้องการให้รันโปรแกรมทุกครั้ง - ที่นี่, ฉันแค่แสดงข้อความ) ถ้าภายใน ITERATE มีวัตถุประสงค์เพื่อจับค่า 0 เนื่องจาก $ (คำ ... ) จะผิดพลาดเป็นอย่างอื่น
โปรดสังเกตว่ามีการใช้สตริงที่เพิ่มขึ้นเพื่อทำหน้าที่เป็นตัวนับเนื่องจากบิวด์ $ (คำ ... ... ) สามารถจัดให้มีการนับภาษาอาหรับ แต่สิ่งที่ทำไม่สนับสนุนการดำเนินการทางคณิตศาสตร์เป็นอย่างอื่น (คุณไม่สามารถกำหนด 1 + 1 ให้กับบางสิ่ง นอกเสียจากว่าคุณกำลังเรียกบางอย่างจากเชลล์เพื่อให้สำเร็จหรือใช้การทำงานของแมโครที่ซับซ้อนเท่ากัน) วิธีนี้ใช้งานได้ดีสำหรับตัวนับ INCREMENTAL แต่ก็ไม่ค่อยดีสำหรับ DECREMENT
ฉันไม่ได้ใช้สิ่งนี้ด้วยตัวเอง แต่เมื่อเร็ว ๆ นี้ฉันจำเป็นต้องเขียนฟังก์ชันแบบเรียกซ้ำเพื่อประเมินการพึ่งพาของไลบรารีในสภาพแวดล้อมการสร้างแบบ multi-binary, multi-library ที่คุณจำเป็นต้องรู้เพื่อนำมาไว้ในห้องสมุดอื่น ๆ ตัวเองมีการอ้างอิงอื่น ๆ (บางอย่างแตกต่างกันไปขึ้นอยู่กับพารามิเตอร์การสร้าง) และฉันใช้วิธี $ (eval) และตัวนับคล้ายกับข้างต้น (ในกรณีของฉันตัวนับใช้เพื่อให้แน่ใจว่าเราจะไม่สิ้นสุด วนรอบและยังเป็นการวินิจฉัยเพื่อรายงานจำนวนการวนซ้ำที่จำเป็น)
อย่างอื่นไม่มีค่าอะไร แต่ไม่มีนัยสำคัญต่อ Q ของ $ OP (eval ... ) ให้วิธีการหลีกเลี่ยงความเกลียดชังภายในของการอ้างอิงวงกลมซึ่งเป็นสิ่งที่ดีและดีที่จะบังคับใช้เมื่อตัวแปรเป็นประเภทแมโคร (intialized ด้วย =), กับการมอบหมายทันที (เริ่มต้นด้วย: =) มีหลายครั้งที่คุณต้องการใช้ตัวแปรภายในการมอบหมายของตนเองและ $ (eval ... ) จะช่วยให้คุณทำเช่นนั้นได้ สิ่งสำคัญที่ควรพิจารณาที่นี่คือในเวลาที่คุณเรียกใช้ eval ตัวแปรจะได้รับการแก้ไขและส่วนที่ได้รับการแก้ไขจะไม่ถูกใช้เป็นมาโครอีกต่อไป หากคุณรู้ว่าคุณกำลังทำอะไรอยู่และคุณพยายามที่จะใช้ตัวแปรใน RHS ของการมอบหมายให้ตัวเองนี่เป็นสิ่งที่คุณต้องการให้เกิดขึ้นโดยทั่วไป
SOMESTRING = foo
# will error. Comment out and re-run
SOMESTRING = pre-${SOMESTRING}
# works
$(eval SOMESTRING = pre${SOMESTRING}
default:
@echo ${SOMESTRING}
ขอให้มีความสุข
สำหรับการสนับสนุนข้ามแพลตฟอร์มให้กำหนดตัวคั่นคำสั่ง (สำหรับการดำเนินการหลายคำสั่งในบรรทัดเดียวกัน)
หากคุณกำลังใช้ MinGW บนแพลตฟอร์ม Windows ตัวคั่นคำสั่งคือ&
:
NUMBERS = 1 2 3 4
CMDSEP = &
doit:
$(foreach number,$(NUMBERS),./a.out $(number) $(CMDSEP))
สิ่งนี้จะประมวลผลคำสั่งที่ต่อกันในหนึ่งบรรทัด:
./a.out 1 & ./a.out 2 & ./a.out 3 & ./a.out 4 &
เป็นที่กล่าวถึงที่อื่น ๆ CMDSEP = ;
ในการใช้งานแพลตฟอร์มระวัง
นี่ไม่ใช่คำตอบที่แท้จริงของคำถาม แต่เป็นวิธีที่ชาญฉลาดในการแก้ไขปัญหาดังกล่าว:
แทนที่จะเขียนไฟล์ที่ซับซ้อนเพียงแค่มอบหมายการควบคุมให้ตัวอย่างเช่นสคริปต์ทุบตีเช่น: makefile
foo : bar.cpp baz.h
bash script.sh
และ script.sh ดูเหมือนว่า:
for number in 1 2 3 4
do
./a.out $number
done
eval echo \$${$(var)}
; \ echo $$ var1; \ ((NUM = NUM + 1)); \ Done all: set_var ที่นี่ SSA_CORE0_MAINEXEC เป็นตัวแปรสภาพแวดล้อมที่มีการตั้งค่าไว้แล้วดังนั้นฉันต้องการให้ค่านั้นได้รับการประเมินหรือพิมพ์โดยใช้ตัวแปร var1 ฉันลองมันตามที่แสดงด้านบน แต่ไม่ทำงาน กรุณาช่วย.
bash
ใช้งานได้ การวนซ้ำเป็นหนึ่งในคุณสมบัติที่สามารถแสดงให้เห็นได้
บางทีคุณสามารถใช้:
xxx:
for i in `seq 1 4`; do ./a.out $$i; done;
คุณสามารถใช้set -e
เป็นคำนำหน้าสำหรับ for-loop ตัวอย่าง:
all:
set -e; for a in 1 2 3; do /bin/false; echo $$a; done
make
<> 0
จะออกทันทีด้วยรหัสทางออก
แม้ว่าเครื่องมือตาราง gnumakeมีจริงwhile
ห่วง (สิ่งที่หมายถึงการเขียนโปรแกรมใน gnumake มีสองหรือสามขั้นตอนของการดำเนินการ) interval
ถ้าสิ่งที่จำเป็นต้องมีรายชื่อซ้ำมีวิธีที่เรียบง่ายด้วย เพื่อความสนุกเราได้แปลงตัวเลขเป็นฐานสิบหกด้วย:
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))
เอาท์พุท:
./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
วิธีแก้ปัญหาแมโครที่ง่ายและอิสระต่อเชลล์และแพลตฟอร์มบริสุทธิ์คือ ...
%sequence = $(if $(word ${1},${2}),$(wordlist 1,${1},${2}),$(call %sequence,${1},${2} $(words _ ${2})))
$(foreach i,$(call %sequence,10),$(info ./a.out ${i}))
#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.