Làm cách nào tôi có thể sử dụng cú pháp Bash trong các mục tiêu Makefile?


208

Tôi thường thấy cú pháp Bash rất hữu ích, ví dụ như thay thế quá trình như trongdiff <(sort file1) <(sort file2) .

Có thể sử dụng các lệnh Bash như vậy trong Makefile không? Tôi đang nghĩ về một cái gì đó như thế này:

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

Trong GNU Make 3.80, điều này sẽ báo lỗi vì nó sử dụng shellthay vì bashthực thi các lệnh.


Đây chính xác là vấn đề của tôi, tôi đã mất ít nhất một giờ để tìm câu hỏi này! Tôi để lại thông báo lỗi của mình ở đây để độc giả tương lai có thể tìm thấy nó: /bin/sh: -c: line 0: syntax error near unexpected token ('`
David

Câu trả lời:


380

Từ tài liệu 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.

Vì vậy, đặt SHELL := /bin/bashở đầu trang điểm của bạn, và bạn nên đi.

BTW: Bạn cũng có thể làm điều này cho một mục tiêu, ít nhất là cho GNU Make. Mỗi mục tiêu có thể có các bài tập biến riêng, như thế này:

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"

Điều đó sẽ in:

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

Xem "Giá trị biến đổi theo mục tiêu cụ thể" trong tài liệu để biết thêm chi tiết. Dòng đó có thể đi bất cứ nơi nào trong Makefile, nó không phải ở ngay trước mục tiêu.


43
500 tiền thưởng đang chờ báo giá từ man. Nói về thời gian. : P
SiddharthaRT

3
@inLoveWithPython Vâng, infothực sự, nhưng, tôi đoán nó thực sự đã giúp Andy. Tôi biết tôi đã có những ngày như thế ...
derobert

3
nếu nghi ngờ, @derobert có nghĩa đen: SHELL=/bin/bashlà dòng đầu tiên của Makefile (hoặc ngay sau bình luận).
Yauhen Yakimovich

1
Cảm ơn @derobert đã giải quyết vấn đề của tôi trong stackoverflow.com/questions/26806832/iêng
Chandan Choudhury

2
Có thể thay đổi biến SHELL chỉ cho một mục tiêu cụ thể mà không bị ảnh hưởng?
antred

18

Bạn có thể gọi bashtrực tiếp, sử dụng -ccờ:

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

Tất nhiên, bạn có thể không thể chuyển hướng đến biến $ @, nhưng khi tôi cố gắng thực hiện điều này, tôi đã nhận được -bash: $@: ambiguous redirectmột thông báo lỗi, vì vậy bạn có thể muốn xem xét điều đó trước khi bạn quá hiểu điều này (mặc dù tôi sử dụng bash 3.2.s Something, vì vậy có thể bạn làm việc khác đi).


4

Nếu tính di động là quan trọng, bạn có thể không muốn phụ thuộc vào lớp vỏ cụ thể trong Makefile của mình. Không phải tất cả các môi trường có bash có sẵn.


4

Bạn có thể gọi bash trực tiếp trong Makefile của mình thay vì sử dụng shell mặc định:

bash -c "ls -al"

thay vì:

ls -al

1
Lưu ý rằng makebỏ qua giá trị của biến môi trường SHELL.
choroba

2

Có một cách để làm điều này mà không cần thiết lập rõ ràng biến SHELL của bạn để trỏ đến bash. Điều này có thể hữu ích nếu bạn có nhiều tệp tạo tệp do SHELL không được kế thừa bởi các tệp tạo tệp tiếp theo hoặc được lấy từ môi trường. Bạn cũng cần chắc chắn rằng bất kỳ ai biên dịch mã của bạn đều cấu hình hệ thống của họ theo cách này.

Nếu bạn chạy sudo dpkg-reconfigure dashvà trả lời 'không' cho lời nhắc, hệ thống của bạn sẽ không sử dụng dấu gạch ngang làm vỏ mặc định. Sau đó, nó sẽ trỏ đến bash (ít nhất là trong Ubuntu). Lưu ý rằng sử dụng dấu gạch ngang làm vỏ hệ thống của bạn sẽ hiệu quả hơn một chút.


1
Khi được gọi dưới tên sh, bash chạy trong chế độ tương thích ( set -o posix). Chức năng mà OP đang cố gắng sử dụng, thay thế quá trình, không khả dụng trong chế độ này.
Charles Duffy

1

Một cách cũng hiệu quả là đặt nó theo cách này trong dòng đầu tiên của mục tiêu của bạn:

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.