GNU/Linux >> Belajar Linux >  >> Linux

Apa perbedaan antara #!/usr/bin/env bash dan #!/usr/bin/bash?

Jika skrip shell dimulai dengan #!/bin/bash , mereka akan selalu berjalan dengan bash dari /bin . Namun jika mereka mulai dengan #!/usr/bin/env bash , mereka akan mencari bash di $PATH dan kemudian mulai dengan yang pertama yang dapat mereka temukan.

Mengapa ini berguna? Asumsikan Anda ingin menjalankan bash skrip, yang memerlukan bash 4.x atau yang 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 membuat bash Anda sendiri dari awal, menempatkannya di ~/bin Misalnya. Dan Anda juga dapat memodifikasi $PATH Anda variabel di .bash_profile Anda file untuk menyertakan ~/bin sebagai entri pertama (PATH=$HOME/bin:$PATH sebagai ~ tidak akan diperluas di $PATH ). Jika sekarang Anda memanggil bash , pertama-tama shell akan mencarinya di $PATH berurutan, jadi dimulai dengan ~/bin , di mana ia akan menemukan bash Anda . Hal yang sama terjadi jika skrip mencari bash menggunakan #!/usr/bin/env bash , jadi skrip ini sekarang akan bekerja di sistem Anda menggunakan bash khusus Anda membangun.

Satu kelemahannya adalah, hal ini dapat menyebabkan perilaku yang tidak terduga, mis. skrip yang sama pada mesin yang sama dapat berjalan dengan juru bahasa yang berbeda untuk lingkungan atau pengguna yang berbeda dengan jalur pencarian yang berbeda, menyebabkan semua jenis sakit kepala.

Kelemahan terbesar dengan env adalah bahwa beberapa sistem hanya 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 ekspresi dikutip) dan dengan demikian env akan mencari juru bahasa bernama <interpreter> <arg> . Perhatikan bahwa ini bukan masalah dari env perintah itu sendiri, yang selalu mengizinkan beberapa parameter untuk dilewati tetapi dengan parser shebang dari sistem yang mem-parsing baris ini bahkan sebelum memanggil env . Sementara ini telah diperbaiki pada sebagian besar sistem tetapi jika skrip Anda ingin sangat portabel, Anda tidak dapat mengandalkan bahwa ini telah diperbaiki pada sistem yang akan Anda jalankan.

Itu bahkan dapat memiliki implikasi keamanan, mis. jika sudo tidak dikonfigurasi untuk membersihkan lingkungan atau $PATH dikeluarkan dari pembersihan. Izinkan saya mendemonstrasikan ini:

Biasanya /bin adalah tempat yang terlindungi dengan baik, hanya root mampu mengubah apa pun di sana. Namun, direktori home Anda tidak, program apa pun yang Anda jalankan dapat mengubahnya. Itu berarti kode berbahaya dapat menempatkan bash palsu ke beberapa direktori tersembunyi, ubah .bash_profile Anda untuk memasukkan direktori itu ke dalam $PATH Anda , jadi semua skrip menggunakan #!/usr/bin/env bash akan berakhir dengan bash palsu itu . Jika sudo menyimpan $PATH , Anda berada dalam masalah besar.

Misalnya. pertimbangkan alat untuk 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 "[email protected]"

Mari kita membuat skrip sederhana sample.sh :

#!/usr/bin/env bash

echo "Hello World"

Bukti konsep (pada sistem di mana 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 terletak di /bin dan jika Anda tidak ingin menempatkannya di sana karena alasan apa pun, sebenarnya bukan masalah untuk menempatkan symlink di /bin yang menunjuk ke lokasi aslinya (atau mungkin /bin itu sendiri adalah symlink), jadi saya akan selalu menggunakan #!/bin/sh dan #!/bin/bash . Terlalu banyak yang akan rusak jika ini tidak berfungsi lagi. Bukannya POSIX akan membutuhkan posisi ini (POSIX tidak membakukan nama jalur dan karenanya bahkan tidak membakukan fitur shebang sama sekali) tetapi mereka sangat umum, bahkan jika sistem tidak akan menawarkan /bin/sh , mungkin masih mengerti #!/bin/sh dan tahu apa yang harus dilakukan dengannya dan semoga itu hanya untuk kompatibilitas dengan kode yang ada.

Tetapi untuk interpreter opsional yang lebih modern, tidak standar, seperti Perl, PHP, Python, atau Ruby, itu tidak benar-benar ditentukan di mana pun mereka seharusnya berada. Mereka mungkin ada di /usr/bin tetapi mereka mungkin juga berada di /usr/local/bin atau di cabang hierarki yang sama sekali berbeda (/opt/... , /Applications/... , dll.). Itu sebabnya ini sering menggunakan #!/usr/bin/env xxx sintaks shebang.


Menggunakan #!/usr/bin/env NAME membuat shell mencari kecocokan pertama NAME dalam variabel lingkungan $PATH. Ini bisa berguna jika Anda tidak mengetahui jalur absolut atau tidak ingin menelusurinya.


Menjalankan perintah melalui /usr/bin/env memiliki keuntungan mencari apa pun versi default program di env Anda saat ini penyetrikaan.

Dengan cara ini, Anda tidak perlu mencarinya di tempat tertentu di sistem, karena jalur tersebut mungkin berada di lokasi yang berbeda di sistem yang berbeda. Selama berada di jalur Anda, ia akan menemukannya.

Satu kelemahannya adalah Anda tidak akan dapat memberikan lebih dari satu argumen (mis. Anda tidak akan dapat menulis /usr/bin/env awk -f ) jika Anda ingin mendukung Linux, karena POSIX tidak jelas tentang bagaimana garis harus ditafsirkan, dan Linux menafsirkan semuanya setelah spasi pertama untuk menunjukkan satu argumen. Anda dapat menggunakan /usr/bin/env -S pada beberapa versi env untuk mengatasi ini, tetapi kemudian skrip akan menjadi kurang portabel dan rusak pada sistem yang cukup baru (mis. bahkan Ubuntu 16.04 jika tidak lebih baru).

Kelemahan lainnya adalah karena Anda tidak memanggil executable eksplisit, ada potensi kesalahan, dan pada masalah keamanan sistem multipengguna (jika seseorang berhasil membuat executable mereka disebut 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). Namun dalam situasi di mana keamanan menjadi fokus, yang terakhir lebih disukai, karena membatasi kemungkinan injeksi kode.


Linux
  1. Bagaimana Linux Menangani Beberapa Pemisah Jalur Berturut-turut (/home////username///file)?

  2. Apa Perbedaan Antara /sbin/nologin Dan /bin/false?

  3. Perbedaan Antara /opt Dan /usr/local?

  1. Linux – Menggabungkan /usr/bin Dan /usr/sbin Ke /bin (gnu/linux)?

  2. Instal binari ke /bin, /sbin, /usr/bin dan /usr/sbin, interaksi dengan --prefix dan DESTDIR

  3. cmake --version menunjuk ke /usr/bin/cmake sementara cmake menunjuk ke /usr/local/bin

  1. Kapan saya harus menggunakan #!/bin/bash dan kapan #!/bin/sh?

  2. Perbedaan antara /bin dan /usr/bin

  3. Apa perbedaan antara /tmp dan /run?