"Command not found" ketika fungsi sudo'ing dari ~ / .zshrc

10

Saya memiliki fungsi di ~/.zshrc:

findPort() {
    lsof -t -i :$1
}

Doa yang biasa adalah findPort 3306.

Saya ingin menjalankannya dengan hak istimewa yang ditinggikan. Tapi saya mendapatkan "perintah tidak ditemukan".

  git 🍔 sudo findPort 3306
sudo: findPort: command not found

Saya kira alasannya adalah bahwa pengguna root berjalan sebagai shell non-interaktif (dengan demikian tidak merujuk ke .zshrc), atau merujuk ke yang berbeda .zshrc .

Saya telah melihat pertanyaan serupa tentang alias, tetapi tidak ada pertanyaan tentang fungsi yang ditentukan pengguna. Jawaban untuk masalah ini terkait aliasdengan menambahkan alias ke ~/.zshrc:

alias sudo='nocorrect sudo '

Atau mungkin:

alias sudo='sudo '

Saya sudah mencoba kedua solusi ini, dan masalahnya masih ada (ya saya sudah meluncurkan shell).

Saya juga mencoba menjalankan sudo chshuntuk memastikan bahwa shell root saya berjalan di bawah zsh. Tak satu pun dari solusi ini menghilangkan masalah "perintah tidak ditemukan".

Apakah ada cara untuk menjalankan fungsi yang ditentukan pengguna saya di bawah sudo?

Birchlabs
sumber
Lihat juga: unix.stackexchange.com/questions/181414/… (tidak menandai karena zsh memiliki triknya sendiri)
muru

Jawaban:

13

sudoberjalan perintah langsung, tidak melalui shell, dan bahkan jika itu berlari shell untuk menjalankan perintah itu, itu akan menjadi shell doa baru, dan bukan salah satu yang berbunyi Anda ~/.zshrc(bahkan jika itu mulai shell interaktif, mungkin akan membaca root's ~/.zshrc, bukan milik Anda kecuali Anda telah mengkonfigurasi sudountuk tidak mereset $HOMEvariabel).

Di sini, Anda perlu memberi tahu sudountuk memulai zshshell baru , dan mengatakan itu zshuntuk membaca Anda ~/.zshrcsebelum menjalankan fungsi itu:

sudo zsh -c '. $0; "$@"' ~/.zshrc findPort 3306

Atau:

sudo zsh -c '. $0; findPort 3306' ~/.zshrc

Atau untuk berbagi fungsi zsh Anda saat ini dengan yang baru zshdipanggil oleh sudo:

sudo zsh -c "$(functions); findPort 3306"

Meskipun Anda mungkin mendapatkan daftar argumen terlalu lama jika Anda memiliki banyak fungsi yang didefinisikan (seperti saat menggunakan sistem penyelesaian). Jadi, Anda mungkin ingin membatasinya ke findPortfungsi (dan setiap fungsi lain yang diandalkannya jika ada):

sudo zsh -c "$(functions findPort); findPort 3306"

Anda juga bisa:

sudo zsh -c "(){$functions[findPort]} 3306"

Untuk menyematkan kode findPortfungsi dalam fungsi anonim yang Anda gunakan argumen 3306. Atau bahkan:

sudo zsh -c "$functions[findPort]" findPort 3306

(script inline diteruskan ke -c adalah tubuh fungsi).

Anda dapat menggunakan fungsi pembantu seperti:

zsudo() sudo zsh -c "$functions[$1]" "$@"

Jangan gunakan:

sdo () {sudo zsh -c "() {$ functions [$ 1]} $ {@: 2}"}

Sebagai argumen sdoakan menjalani tingkat penguraian shell. Membandingkan:

$ e() echo "$@"
$ sdo e 'tname;uname'
tname
Linux
$ zsudo e 'tname;uname'
tname;uname
Stéphane Chazelas
sumber
Saya butuh solusi yang sesingkat mengetik sudo. Saya dapat mengadaptasi solusi fungsi anonim Anda untuk melakukan hal itu. Saya telah menambahkan fungsi berikut ke saya ~/.zshrc, yang merupakan fungsi untuk menjalankan fungsi lain dengan hak istimewa yang ditingkatkan:sdo() { sudo zsh -c "(){$functions[$1]} ${@:2}" }
Birchlabs
1
@Birchlabs, lihat edit
Stéphane Chazelas
Terima kasih; Saya telah memperbarui jawaban saya untuk menggunakan pintasan baru yang Anda usulkan.
Birchlabs
Menambahkan definisi fungsi ke skrip yang dieksekusi melalui sudo adalah cerdas. Tetapi tidak cukup pintar jika fungsi itu menggunakan fungsi lain (autoloaded atau tidak).
Damien Flament
3

Solusi yang sangat sederhana bagi saya adalah menggunakan shell interaktif menggunakan sudo -s, yang tampaknya berfungsi pada versi berkas macOS saya dari zsh (5.2). Ini memberi saya fungsi dari ~/.zshrc.

Dari manual sudo, yang sebenarnya tidak mengisyaratkan perilaku ini:

-s, --shell
Jalankan shell yang ditentukan oleh variabel lingkungan SHELL jika sudah disetel atau shell yang ditentukan oleh entri basis data kata sandi pengguna yang memohon. Jika suatu perintah ditentukan, perintah itu diteruskan ke shell untuk dieksekusi melalui opsi-c shell. Jika tidak ada perintah yang ditentukan, shell interaktif dijalankan.

Saya tidak yakin apa kasus penggunaan Anda, tetapi saya curiga Anda sedang mencari solusi interaktif.

jhat
sumber
Ini memang berhasil. Meskipun itu bukan alur kerja yang ada dalam pikiran saya. Keinginan saya adalah untuk tetap berada di prompt seperti pengguna saya yang biasa, dan meninggikan fungsi yang ditentukan pengguna saja myFunc, dengan mengetik sudo myFunc- dengan cara yang sama saya akan meningkatkan proses apa pun (seperti sudo rm -rf .). Solusi ini meningkatkan seluruh fungsi prompt dan semua fungsi saya di masa depan, serta mengubah pengguna saya untuk semua fungsi di masa depan - yang sedikit berlebihan.
Birchlabs
The sudo -sperintah akan meluncurkan contoh lain dari shell Anda sebagai superuser. Jika Anda menjalankan perintah itu secara interaktif, shell baru Anda akan interaktif. Tetapi perintah itu sudo -s findPort 3306akan menjalankan perintah findPort 3306di shell Anda sebagai superuser kemudian keluar dengan kode status dari perintah itu.
Damien Flament
2

Saya dapat menghasilkan steno yang dapat digunakan kembali untuk salah satu solusi yang dijelaskan dalam jawaban Stéphane Chazelas . [Sunting: Stéphane telah mengulangi pada pintasan asli yang saya usulkan; kode yang dijelaskan di sini adalah versi yang lebih baru, dari pembuatannya]

Masukkan ini ke Anda ~/.zshrc:

sdo() sudo zsh -c "$functions[$1]" "$@"

Sekarang Anda dapat menggunakan sdosebagai "hanya sudountuk fungsi yang ditentukan pengguna".

Untuk mengonfirmasi bahwa sdoberfungsi: Anda dapat mencobanya pada fungsi yang ditentukan pengguna yang mencetak nama pengguna Anda.

 birch@server ~/ 🍔 test() whoami

 birch@server ~/ 🍔 test
birch

 birch@server ~/ 🍔 sdo test
root
Birchlabs
sumber
0

Ini sepertinya bekerja untuk saya:

function sudo (){
  args="$@"
  /run/wrappers/bin/sudo -u "$USER" zsh -i -c "$args"
}
Chris Stryczynski
sumber