ฉันจะใช้ไวยากรณ์ Bash ในเป้าหมาย Makefile ได้อย่างไร


208

ฉันมักจะพบทุบตีdiff <(sort file1) <(sort file2)ไวยากรณ์ประโยชน์มากเปลี่ยนตัวกระบวนการเช่นเหมือนใน

เป็นไปได้ไหมที่จะใช้คำสั่ง Bash ใน Makefile ฉันกำลังคิดถึงสิ่งนี้:

file-differences:
    diff <(sort file1) <(sort file2) > $@

ใน GNU Make 3.80 ของฉันนี่จะทำให้เกิดข้อผิดพลาดเนื่องจากใช้shellแทนbashการใช้คำสั่ง


นี่เป็นปัญหาของฉันอย่างแน่นอนฉันใช้เวลาอย่างน้อยหนึ่งชั่วโมงในการค้นหาคำถามนี้! ฉันปล่อยให้ข้อความแสดงข้อผิดพลาดของฉันที่นี่เพื่อให้ผู้อ่านในอนาคตสามารถค้นหาได้: /bin/sh: -c: line 0: syntax error near unexpected token ('`
เดวิด

คำตอบ:


380

จากเอกสารของ GNU Make

5.3.1 Choosing the Shell
------------------------

The program used as the shell is taken from the variable `SHELL'.  If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.

ดังนั้นใส่SHELL := /bin/bashที่ด้านบนของ makefile ของคุณและคุณควรจะไปดี

BTW: คุณสามารถทำสิ่งนี้เพื่อเป้าหมายเดียวอย่างน้อยก็สำหรับ GNU Make แต่ละเป้าหมายสามารถมีการกำหนดตัวแปรของตนเองเช่นนี้:

all: a b

a:
    @echo "a is $$0"

b: SHELL:=/bin/bash   # HERE: this is setting the shell for b only
b:
    @echo "b is $$0"

จะพิมพ์:

a is /bin/sh
b is /bin/bash

ดู "ค่าตัวแปรเฉพาะเป้าหมาย" ในเอกสารประกอบสำหรับรายละเอียดเพิ่มเติม บรรทัดนั้นสามารถไปที่ใดก็ได้ใน Makefile โดยไม่จำเป็นต้องอยู่หน้าเป้าหมายทันที


43
500 manรางวัลรอให้ใบเสนอราคาจาก พูดคุยเกี่ยวกับการกำหนดเวลา : P
SiddharthaRT

3
@inLoveWithPython infoจริง ๆ แล้ว แต่ฉันคิดว่ามันช่วยแอนดี้ได้จริงๆ ฉันรู้ว่าฉันมีวันแบบนั้น ...
derobert

3
หากมีข้อสงสัย @derobert หมายตามตัวอักษร: SHELL=/bin/bashเป็นบรรทัดแรกของ Makefile (หรือหลังจากความคิดเห็น)
Yauhen Yakimovich

1
ขอบคุณ @derobert แก้ปัญหาของฉันในstackoverflow.com/questions/26806832/…
Chandan Choudhury

2
เป็นไปได้ไหมที่จะเปลี่ยนตัวแปร SHELL สำหรับเป้าหมายที่เฉพาะเจาะจงหนึ่งอัน
59

18

คุณสามารถโทรbashโดยตรงใช้-cธง:

bash -c "diff <(sort file1) <(sort file2) > $@"

แน่นอนคุณอาจไม่สามารถเปลี่ยนเส้นทางไปยังตัวแปร $ @ แต่เมื่อฉันพยายามทำสิ่งนี้ฉันได้รับ-bash: $@: ambiguous redirectเป็นข้อความแสดงข้อผิดพลาดดังนั้นคุณอาจต้องการตรวจสอบก่อนที่คุณจะได้รับสิ่งนี้ (แม้ว่าฉัน ใช้ bash 3.2.something ดังนั้นบางทีงานของคุณอาจแตกต่างออกไป)


4

หากการพกพามีความสำคัญคุณอาจไม่ต้องการพึ่งพาเชลล์เฉพาะใน Makefile ของคุณ ไม่ใช่ทุกสภาพแวดล้อมที่มีการทุบตี


4

คุณสามารถโทร bash โดยตรงภายใน Makefile ของคุณแทนการใช้เปลือกเริ่มต้น:

bash -c "ls -al"

แทน:

ls -al

1
โปรดทราบว่าmakeจะไม่สนใจค่าของตัวแปรสภาพแวดล้อม SHELL
choroba

2

มีวิธีการทำเช่นนี้โดยไม่ตั้งค่าตัวแปร SHELL ของคุณให้ชี้ไปที่ทุบตีอย่างชัดเจน สิ่งนี้มีประโยชน์หากคุณมี makefiles หลายอันเนื่องจาก SHELL ไม่ได้รับการสืบทอดโดย makefiles ที่ตามมาหรือนำมาจากสภาพแวดล้อม คุณต้องแน่ใจว่าทุกคนที่รวบรวมรหัสของคุณกำหนดค่าระบบด้วยวิธีนี้

หากคุณเรียกใช้sudo dpkg-reconfigure dashและตอบ 'ไม่' ต่อพรอมต์ระบบของคุณจะไม่ใช้เส้นประเป็นเชลล์เริ่มต้น จากนั้นจะชี้ไปที่ทุบตี (อย่างน้อยใน Ubuntu) โปรดทราบว่าการใช้ dash เป็นเชลล์ระบบของคุณจะมีประสิทธิภาพมากกว่า


1
เมื่อเรียกใช้ภายใต้ชื่อshbash จะทำงานในโหมดความเข้ากันได้ ( set -o posix) ฟังก์ชันการทำงานของ OP กำลังพยายามใช้การทดแทนกระบวนการไม่สามารถใช้ได้ในโหมดนี้
Charles Duffy

1

วิธีหนึ่งที่ใช้งานได้ก็คือการวางไว้ในบรรทัดแรกของเป้าหมายของคุณ:

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.