Di header skrip Bash, apa perbedaan antara kedua pernyataan itu:
#!/usr/bin/env bash
#!/usr/bin/bash
Ketika saya berkonsultasi env
halaman manual , saya mendapatkan definisi ini:
env - run a program in a modified environment
Apa artinya?
Di header skrip Bash, apa perbedaan antara kedua pernyataan itu:
#!/usr/bin/env bash
#!/usr/bin/bash
Ketika saya berkonsultasi env
halaman manual , saya mendapatkan definisi ini:
env - run a program in a modified environment
Apa artinya?
Jawaban:
Menjalankan melalui perintah /usr/bin/env
memiliki manfaat mencari apa pun versi default dari program ini adalah di saat env ironment.
Dengan cara ini, Anda tidak perlu mencarinya di tempat tertentu pada sistem, karena jalur tersebut mungkin berada di lokasi yang berbeda di sistem yang berbeda. Selama itu di jalan Anda, itu akan menemukannya.
Salah satu kelemahannya adalah Anda tidak akan dapat melewati lebih dari satu argumen (mis. Anda tidak akan bisa menulis /usr/bin/env awk -f
) jika Anda ingin mendukung Linux, karena POSIX tidak jelas tentang bagaimana garis harus ditafsirkan, dan Linux menginterpretasikan semuanya setelah yang pertama. ruang untuk menunjukkan satu argumen. Anda dapat menggunakan /usr/bin/env -S
beberapa versi env
untuk menyiasatinya, tetapi skrip tersebut akan menjadi semakin portabel dan rusak pada sistem yang cukup baru (mis. Bahkan Ubuntu 16.04 jika tidak lebih baru).
Kelemahan lain adalah bahwa karena Anda tidak memanggil executable eksplisit, itu punya potensi kesalahan, dan pada masalah keamanan sistem multi-pengguna (jika seseorang berhasil mendapatkan executable mereka dipanggil bash
di jalur Anda, misalnya).
#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash #gives you explicit control on a given system of what executable is called
Dalam beberapa situasi, yang pertama mungkin lebih disukai (seperti menjalankan skrip python dengan beberapa versi python, tanpa harus mengerjakan ulang baris yang dapat dieksekusi). Tetapi dalam situasi di mana keamanan adalah fokus, yang terakhir lebih disukai, karena membatasi kemungkinan injeksi kode.
#!/usr/bin/env echo Hello
mengeluh: /usr/bin/env: echo Hello: No such file or directory
. Rupanya itu berlaku echo Hello
sebagai argumen tunggal /usr/bin/env
.
env
Perintah ini tentu saja memungkinkan argumen untuk diteruskan ke perintah. Masalahnya adalah semantik #!
baris, dan itu tergantung pada kernel. Kernel Linux terbaru memang memungkinkan hal-hal seperti #!/usr/bin/env command args
, tetapi kernel Linux yang lebih tua dan sistem lainnya tidak.
Menggunakan #!/usr/bin/env NAME
membuat shell mencari kecocokan pertama NAME dalam variabel lingkungan $ PATH. Ini bisa bermanfaat jika Anda tidak mengetahui jalan absolut atau tidak ingin mencarinya.
Alih-alih secara eksplisit mendefinisikan jalur ke penerjemah seperti di /usr/bin/bash/
, dengan menggunakan perintah env, penerjemah dicari dan diluncurkan dari mana pun pertama kali ditemukan. Ini memiliki kelebihan dan kekurangan
Jika skrip shell mulai dengan #!/bin/bash
, mereka akan selalu dijalankan dengan bash
dari /bin
. Jika mereka Namun mulai dengan #!/usr/bin/env bash
, mereka akan mencari bash
di $PATH
dan kemudian mulai dengan yang pertama mereka dapat menemukan.
Mengapa ini berguna? Asumsikan Anda ingin menjalankan bash
skrip, yang memerlukan bash 4.x atau lebih baru, namun sistem Anda hanya memiliki bash
3.x diinstal dan saat ini distribusi Anda tidak menawarkan versi yang lebih baru atau Anda bukan administrator dan tidak dapat mengubah apa yang diinstal pada sistem itu .
Tentu saja, Anda dapat mengunduh kode sumber bash dan membangun bash Anda sendiri dari awal, ~/bin
misalnya sebagai contoh. Dan Anda juga dapat memodifikasi $PATH
variabel Anda di .bash_profile
file Anda untuk dimasukkan ~/bin
sebagai entri pertama ( PATH=$HOME/bin:$PATH
karena ~
tidak akan diperluas dalam $PATH
). Jika sekarang Anda menelepon bash
, shell pertama-tama akan mencarinya secara $PATH
berurutan, jadi itu dimulai dengan ~/bin
, di mana ia akan menemukan bash
. Hal yang sama terjadi jika skrip mencari bash
menggunakan #!/usr/bin/env bash
, jadi skrip ini sekarang akan bekerja pada sistem Anda menggunakan custom bash
build Anda.
Salah satu kelemahannya adalah, hal ini dapat menyebabkan perilaku yang tidak terduga, misalnya skrip yang sama pada mesin yang sama dapat berjalan dengan penerjemah berbeda untuk lingkungan yang berbeda atau pengguna dengan jalur pencarian yang berbeda, menyebabkan semua jenis sakit kepala.
Kelemahan terbesar env
adalah bahwa beberapa sistem hanya akan mengizinkan satu argumen, jadi Anda tidak dapat melakukan ini #!/usr/bin/env <interpreter> <arg>
, karena sistem akan melihat <interpreter> <arg>
sebagai satu argumen (mereka akan memperlakukannya seolah-olah ungkapan itu dikutip) dan dengan demikian env
akan mencari nama juru bahasa <interpreter> <arg>
. Perhatikan bahwa ini bukan masalah env
perintah itu sendiri, yang selalu memungkinkan beberapa parameter dilewati tetapi dengan parser shebang dari sistem yang mem-parsing baris ini sebelum bahkan memanggil env
. Sementara ini telah diperbaiki pada sebagian besar sistem tetapi jika skrip Anda ingin menjadi sangat portabel, Anda tidak dapat mengandalkan bahwa ini telah diperbaiki pada sistem yang akan Anda jalankan.
Ia bahkan dapat memiliki implikasi keamanan, misalnya jika sudo
tidak dikonfigurasi untuk membersihkan lingkungan atau $PATH
dikeluarkan dari pembersihan. Biarkan saya menunjukkan ini:
Biasanya /bin
adalah tempat yang terlindungi dengan baik, hanya root
dapat mengubah apa pun di sana. Direktori rumah Anda tidak, bagaimanapun, program apa pun yang Anda jalankan dapat membuat perubahan padanya. Itu berarti kode jahat dapat menempatkan palsu bash
ke beberapa direktori tersembunyi, memodifikasi Anda .bash_profile
untuk memasukkan direktori itu di Anda $PATH
, sehingga semua skrip yang menggunakan #!/usr/bin/env bash
akhirnya akan berjalan dengan palsu itu bash
. Jika sudo
terus $PATH
, Anda dalam masalah besar.
Misalnya, pertimbangkan alat membuat file ~/.evil/bash
dengan konten berikut:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Mari kita membuat skrip sederhana sample.sh
:
#!/usr/bin/env bash
echo "Hello World"
Bukti konsep (pada sistem tempat sudo
menyimpan $PATH
):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Biasanya semua shell klasik harus ditempatkan di /bin
dan jika Anda tidak ingin menempatkannya di sana untuk alasan apa pun, itu benar-benar bukan masalah untuk menempatkan symlink di /bin
yang menunjuk ke lokasi mereka yang sebenarnya (atau mungkin /bin
itu sendiri adalah symlink), jadi Saya akan selalu pergi dengan #!/bin/sh
dan #!/bin/bash
. Ada terlalu banyak yang akan rusak jika ini tidak berfungsi lagi. Bukan berarti POSIX akan membutuhkan posisi ini (POSIX tidak membakukan nama jalur dan dengan demikian bahkan tidak menstandardisasi fitur shebang sama sekali) tetapi mereka sangat umum, bahwa bahkan jika suatu sistem tidak menawarkan /bin/sh
, mungkin masih akan mengerti #!/bin/sh
dan tahu apa yang harus dilakukan dengannya dan mungkin hanya untuk kompatibilitas dengan kode yang ada.
Tetapi untuk penerjemah yang lebih modern, non standar, opsional seperti Perl, PHP, Python, atau Ruby, itu tidak benar-benar ditentukan di mana pun di mana mereka seharusnya berada. Mereka mungkin dalam /usr/bin
tetapi mereka mungkin juga berada di /usr/local/bin
atau di cabang hirarki yang sama sekali berbeda ( /opt/...
, /Applications/...
, dll). Itu sebabnya ini sering menggunakan #!/usr/bin/env xxx
sintaks shebang.
Saya merasa ini berguna, karena ketika saya tidak tahu tentang env, sebelum saya mulai menulis skrip saya melakukan ini:
type nodejs > scriptname.js #or any other environment
dan kemudian saya memodifikasi baris dalam file ke shebang.
Saya melakukan ini, karena saya tidak selalu ingat di mana nodejs di komputer saya - / usr / bin / atau / bin /, jadi bagi saya env
sangat berguna. Mungkin ada detail dengan ini, tapi ini alasan saya