Saya memiliki cara yang sangat nyaman untuk mengkompilasi proyek saya melalui beberapa baris perintah bash. Tapi sekarang saya perlu mengkompilasinya melalui makefile. Mempertimbangkan, bahwa setiap perintah dijalankan di cangkangnya sendiri, pertanyaan saya adalah apa cara terbaik untuk menjalankan perintah bash multi-baris, bergantung satu sama lain, di makefile? Misalnya seperti ini:
for i in `find`
do
all="$all $i"
done
gcc $all
Juga, dapatkah seseorang menjelaskan mengapa bahkan perintah baris tunggal bash -c 'a=3; echo $a > file'
berfungsi dengan benar di terminal, tetapi membuat file kosong dalam kasus makefile?
Jawaban:
Anda dapat menggunakan garis miring terbalik untuk kelanjutan garis. Namun perhatikan bahwa shell menerima seluruh perintah yang digabungkan menjadi satu baris, jadi Anda juga perlu mengakhiri beberapa baris dengan titik koma:
Tetapi jika Anda hanya ingin mengambil seluruh daftar yang dikembalikan oleh
find
pemanggilan dan meneruskannya kegcc
, Anda sebenarnya tidak memerlukan perintah multiline:Atau, menggunakan
$(command)
pendekatan konvensional shell (perhatikan$
pelolosannya):sumber
Seperti yang ditunjukkan dalam pertanyaan, setiap sub-perintah dijalankan di cangkangnya sendiri . Ini membuat penulisan skrip shell non-trivial sedikit berantakan - tetapi itu mungkin! Solusinya adalah dengan mengkonsolidasikan skrip Anda ke dalam apa yang membuat akan mempertimbangkan satu sub-perintah (satu baris).
Tip untuk menulis skrip shell dalam makefiles:
$
dengan mengganti dengan$$
;
antara perintah\
set -e
mencocokkan penyediaan make untuk dibatalkan pada kegagalan sub-perintah()
atau{}
untuk menekankan keterpaduan dari beberapa urutan baris - bahwa ini bukan urutan perintah makefile yang khasInilah contoh yang terinspirasi oleh OP:
sumber
SHELL := /bin/bash
di makefile Anda untuk mengaktifkan fitur khusus BASH seperti substitusi proses .{
sangat penting untuk mencegah interpretasi{set
sebagai perintah yang tidak diketahui.{}
dan()
membuat perbedaan besar jika Anda terkadang ingin menyalin skrip dan menjalankannya langsung dari prompt shell. Anda dapat mendatangkan malapetaka pada instance shell Anda dengan mendeklarasikan variabel, dan terutama memodifikasi status denganset
, di dalam{}
.()
mencegah skrip mengubah lingkungan Anda, yang mungkin lebih disukai. Contoh ( ini akan mengakhiri sesi shell Anda ):{ set -e ; } ; false
.command ; ## my comment \` (the comment is between
`dan` \ `). Ini tampaknya berfungsi dengan baik kecuali jika Anda menjalankan perintah secara manual (dengan salin dan tempel), riwayat perintah akan menyertakan komentar dengan cara yang merusak perintah (jika Anda mencoba menggunakannya kembali). [Catatan: Penyorotan sintaks rusak untuk komentar ini karena penggunaan garis miring terbalik di dalam backtick.]Apa yang salah dengan hanya menjalankan perintah?
Dan untuk pertanyaan kedua Anda, Anda harus keluar dari
$
dengan menggunakan$$
, yaitubash -c '... echo $$a ...'
.EDIT: Contoh Anda dapat ditulis ulang menjadi satu baris skrip seperti ini:
sumber
Tentu saja, cara yang tepat untuk menulis Makefile adalah dengan mendokumentasikan target mana yang bergantung pada sumber mana. Dalam kasus sepele, solusi yang diusulkan akan membuat
foo
ketergantungan pada dirinya sendiri, tetapi tentu saja,make
cukup pintar untuk melepaskan ketergantungan melingkar. Tetapi jika Anda menambahkan file sementara ke direktori Anda, itu akan "secara ajaib" menjadi bagian dari rantai ketergantungan. Lebih baik membuat daftar eksplisit dependensi sekali dan untuk semua, mungkin melalui skrip.GNU membuat tahu bagaimana menjalankan
gcc
untuk menghasilkan sebuah executable dari sekumpulan.c
dan.h
file, jadi mungkin semua yang Anda butuhkan adalahsumber
Direktif ONESHELL memungkinkan untuk menulis beberapa resep baris untuk dieksekusi dalam pemanggilan shell yang sama.
Namun ada kekurangannya: karakter awalan khusus ('@', '-', dan '+') diinterpretasikan secara berbeda.
https://www.gnu.org/software/make/manual/html_node/One-Shell.html
sumber