Di Ubuntu 16.04.3, saya memiliki skrip bash yang sangat sederhana:
test.sh
[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0
Ketika saya menyebutnya sebagai pengguna non-root me
atau sebagai root
, itu berfungsi seperti yang diharapkan. Jika saya menggunakan sudo ./test.sh
, itu mengeluh tentang kesalahan sintaksis:
$ ./test.sh
true
me /bin/bash ./test.sh
$ sudo su
# ./test.sh
true
root /bin/bash ./test.sh
# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh
Apa yang menyebabkan ini? Bagaimana saya bisa memperbaikinya sehingga me
dapat menggunakan skrip ini dengan normal dan dengan sudo
?
sudo su
. Jalankan sajasudo -i
atausudo -s
sebaliknya.sudo -i
mengubah lokasi menjadi/root
.sudo su
atausudo -s
jangan ubah lokasi direktori.-s
.Jawaban:
Setiap skrip dimulai dengan Shebang , tanpa itu skrip memulai skrip Anda tidak tahu penerjemah mana yang harus menjalankan skrip 1 Anda dan mungkin - seperti dalam kasus di
sudo ./script.sh
sini - jalankan dengansh
, yang di Ubuntu 16.04 ditautkandash
. The ekspresi kondisional[[
adalahbash
perintah senyawa , sehinggadash
tidak tahu bagaimana menanganinya dan melempar kesalahan Anda temui.Solusinya di sini adalah menambahkan
sebagai baris pertama skrip Anda. Anda mungkin mendapatkan hasil yang sama ketika Anda menyebutnya secara eksplisit dengan
sudo bash ./script.sh
, tetapi shebang adalah cara untuk pergi.Untuk memeriksa shell mana yang menjalankan skrip Anda, tambahkan
echo $0
ke dalamnya. Itu tidak sama denganecho $SHELL
, mengutip wiki.archlinux.org :1: Ketika Anda mulai
./test.sh
denganbash
asumsibash
, hal yang sama berlaku untuksudo su
subkulit.sumber
/bin/sh
.echo $0
Memberi saya nama script:./test.sh
)/proc/$$/exe
poin apa . Anda juga dapat menguji berbagai variabel seperti$BASH_VERSION
,,$ZSH_VERSION
dll. (Tetapi tanda hubung tidak mengatur variabel seperti itu)Seperti yang dijelaskan oleh @dabut , masalahnya di sini adalah skrip Anda tidak memiliki garis shebang . Tanpa shebang,
sudo
akan default untuk mencoba menjalankan file menggunakan/bin/sh
. Saya tidak dapat menemukannya didokumentasikan di mana pun, tetapi saya mengonfirmasi dengan memeriksasudo
kode sumber tempat saya menemukan yang berikut dalam filepathnames.h
:Ini berarti "atur jika variabel
_PATH_BSHELL
tidak ditentukan, atur ke/bin/sh
". Kemudian, dalamconfigure
skrip yang disertakan dalam tarball sumber, kami memiliki:Lingkaran ini akan mencari
/bin/bash
,/usr/bin/sh
,/sbin/sh
,/usr/sbin/sh
atau/bin/ksh
dan kemudian menetapkan_PATH_BSHELL
untuk mana ditemukan pertama kali . Karena/bin/sh
itu yang pertama dalam daftar dan itu ada,_PATH_BSHELL
diatur ke/bin/sh
. Hasil dari semua ini adalah bahwa shell defaultsudo
kecuali ditentukan lain/bin/sh
.Jadi,
sudo
akan secara default menjalankan hal-hal menggunakan/bin/sh
dan, pada Ubuntu, yang merupakan symlink kedash
, shell minimal yang sesuai dengan POSIX:The
[[
konstruk fitur bash, itu tidak didefinisikan oleh standar POSIX dan tidak dimengerti olehdash
:Secara terperinci, dalam tiga doa Anda mencoba:
./test.sh
Tidak ada
sudo
; tanpa adanya garis shebang, shell Anda akan mencoba untuk mengeksekusi file itu sendiri. Karena Anda menjalankanbash
, ini akan berjalanbash ./test.sh
dan bekerja secara efektif .sudo su
diikuti oleh./test.sh
.Di sini, Anda memulai shell baru untuk pengguna
root
. Ini akan menjadi apa pun shell yang didefinisikan dalam$SHELL
variabel lingkungan untuk pengguna itu dan, pada Ubuntu, shell default root adalahbash
:sudo ./test.sh
Di sini, Anda membiarkan
sudo
menjalankan perintah secara langsung. Karena shell defaultnya/bin/sh
seperti dijelaskan di atas, ini menyebabkannya menjalankan skrip dengan/bin/sh
, yang manadash
dan gagal karenadash
tidak mengerti[[
.Catatan : perincian tentang bagaimana
sudo
menyetel shell default tampaknya sedikit lebih rumit. Saya mencoba mengubah file yang disebutkan dalam jawaban saya untuk menunjuk/bin/bash
tetapisudo
masih default ke/bin/sh
. Jadi harus ada beberapa tempat lain dalam kode sumber di mana shell default didefinisikan. Namun demikian, poin utama (yangsudo
defaultnyash
) masih berlaku.sumber
/bin/sh
dari pesan kesalahan - apa lagi yang mungkin terjadi? Pertanyaannya dijawab dengan indah di shell apa yang digunakan sudo · SO , lihat jugaman sudo
, bagian COMMAND EXECUTION . Ternyatasudo
tidak menggunakan shell perantara !execve
panggilan sistem yang secara defaultsh
. Dan tidak, shell perantara tidak relevan, ini bukan tentang shell yang menjalankan perintah tetapi tentang juru shell yang digunakan untuk membaca skrip shell yang diberikan. Jadi tidak, ia tidak meluncurkan shell perantara tetapi masih membutuhkan shell interpreter untuk skrip shell.