Bagaimana saya bisa menggunakan sintaks Bash dalam target Makefile?

209

Saya sering menemukan sintaks Bash sangat membantu, misalnya proses substitusi seperti di diff <(sort file1) <(sort file2).

Apakah mungkin menggunakan perintah Bash seperti itu di Makefile? Saya sedang memikirkan sesuatu seperti ini:

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

Di GNU Make 3.80 saya ini akan memberikan kesalahan karena menggunakan shellbukannya bashmenjalankan perintah.

jujur
sumber
Ini persis masalah saya, butuh saya setidaknya satu jam untuk menemukan pertanyaan ini! Saya meninggalkan pesan kesalahan saya di sini sehingga pembaca di masa mendatang dapat menemukannya: /bin/sh: -c: line 0: syntax error near unexpected token ('`
David

Jawaban:

381

Dari dokumentasi 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.

Jadi letakkan SHELL := /bin/bashdi bagian atas makefile Anda, dan Anda harus baik-baik saja.

BTW: Anda juga dapat melakukan ini untuk satu target, setidaknya untuk GNU Make. Setiap target dapat memiliki tugas variabelnya sendiri, seperti ini:

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"

Itu akan mencetak:

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

Lihat "Nilai Variabel Target-spesifik" dalam dokumentasi untuk rincian lebih lanjut. Baris itu dapat pergi ke mana saja di Makefile, tidak harus langsung sebelum target.

derobert
sumber
43
500 karunia menunggu kutipan dari man. Bicara tentang penentuan waktu. : P
SiddharthaRT
3
@inLoveWithPython Yah, infosebenarnya, tapi, kurasa itu sangat membantu Andy. Saya tahu saya pernah mengalami hari-hari seperti itu ...
derobert
3
jika ragu, @derobert berarti secara harfiah: SHELL=/bin/bashsebagai baris pertama dari Makefile (atau tepat setelah komentar).
Yauhen Yakimovich
1
Terima kasih @derobert memecahkan masalah saya di stackoverflow.com/questions/26806832/…
Chandan Choudhury
2
Apakah mungkin untuk mengubah variabel SHELL hanya untuk satu target tertentu tetapi membiarkan variabel lainnya tidak tersentuh?
antred
18

Anda dapat menelepon bashlangsung, menggunakan -cbendera:

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

Tentu saja, Anda mungkin tidak dapat mengalihkan ke variabel $ @, tetapi ketika saya mencoba melakukan ini, saya mendapat -bash: $@: ambiguous redirectpesan kesalahan, jadi Anda mungkin ingin melihat ke dalamnya sebelum Anda terlalu ke ini (meskipun saya menggunakan bash 3.2.something, jadi mungkin milik Anda bekerja secara berbeda).

Chris Lutz
sumber
4

Jika portabilitas penting, Anda mungkin tidak ingin bergantung pada shell tertentu di Makefile Anda. Tidak semua lingkungan memiliki pesta.

Menno Smits
sumber
4

Anda dapat memanggil bash langsung di dalam Makefile Anda alih-alih menggunakan shell default:

bash -c "ls -al"

dari pada:

ls -al
paxdiablo
sumber
1
Perhatikan bahwa makemengabaikan nilai variabel lingkungan SHELL.
choroba
2

Ada cara untuk melakukan ini tanpa secara eksplisit mengatur variabel SHELL Anda untuk menunjuk ke bash. Ini bisa berguna jika Anda memiliki banyak makefile karena SHELL tidak diwarisi oleh makefiles berikutnya atau diambil dari lingkungan. Anda juga perlu memastikan bahwa siapa pun yang mengkompilasi kode Anda mengonfigurasi sistem mereka dengan cara ini.

Jika Anda menjalankan sudo dpkg-reconfigure dashdan menjawab 'tidak' pada prompt, sistem Anda tidak akan menggunakan tanda hubung sebagai shell default. Kemudian akan menunjuk ke bash (setidaknya di Ubuntu). Perhatikan bahwa menggunakan tanda hubung sebagai shell sistem Anda sedikit lebih efisien.

Bill G
sumber
1
Saat dipanggil dengan nama sh, bash berjalan dalam mode kompatibilitas ( set -o posix). Fungsionalitas yang OP coba gunakan, proses substitusi, tidak tersedia dalam mode ini.
Charles Duffy
1

Salah satu cara yang juga berfungsi adalah dengan meletakkannya di baris pertama dari target Anda:

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"
Nicolas Marshall
sumber