Jalankan baris perintah dengan satu sudo

21

Sebagai contoh jika saya ingin membuat file dan memasukkan teks dalam satu baris saya dapat mengarahkan output ke file dengan menggunakan >operator:

echo "something" > /path/foobar

tetapi jika saya tidak memiliki akses ke folder /path/dan memerlukan sudo hak istimewa, Bagaimana saya bisa mencapai perintah yang sama ini sebagai pengguna normal dengan hak sudo?

Saya mencoba

sudo echo "something" > /path/foobar

tapi itu tidak bekerja, karena sudo hanya jumlah untuk edittetapi tidak untuk bagian kanan
dari>

Tentu, saya bisa menjadi root sebelum dengan sudo suatau menggunakan tee:

echo "something" | sudo tee /path/foobar

Tetapi saya ingin mencari solusi di mana saya dapat bekerja dengan baris terakhir sebagai pengganti via

sudo !!

Apakah tidak ada cara untuk "mendaur ulang" baris terakhir dan tambahkan saja sudodi depan?

rubo77
sumber
Ini bukan duplikat. Saya mengekstrak Qeustion yang asli dan mengubah judul. Sekarang adalah apa yang saya benar-benar cari
rubo77
Ini tentu adalah duplikat, tapi itu agak berbeda sekarang. Sepertinya saya menulis ulang pertanyaan berdasarkan jawaban Boogy, yang baik-baik saja - itu adalah jawaban yang baik. Saya telah mencabut pemungutan suara dekat saya, tetapi itu masih tak terhindarkan (orang-orang sering memilih secara otomatis begitu pertanyaan ada dalam antrian tertutup tanpa memperhatikan masalah ini): alamat komentar @goldilocks ketika ditutup dan saya akan memilih untuk membuka kembali . Anda juga dapat memohon kasus Anda dalam obrolan setelah itu terjadi.
goldilocks
Lihat juga Bagaimana saya bisa alias sudo !!?
Gilles 'SO- berhenti bersikap jahat'

Jawaban:

13

Anda tidak bisa hanya tetap sudodi depan perintah shell, Anda harus memanggil shell untuk mengevaluasi perintah itu lagi (melakukan hal-hal seperti memperluas variabel, membuka file untuk operator pengalihan, dll.). Jadi begitu

sudo bash -c !!

kecuali bahwa ini tidak cukup berhasil, karena !!menyisipkan teks dari perintah sebelumnya, karakter khusus dan semua Anda perlu mengambil teks perintah sebagai string dan meneruskannya sebagai argumen sh. Untungnya, fcbuilt - in bash memungkinkan Anda melakukan itu¹.

sudo bash -c "$(fc -ln -1)"

Atau bahkan, untuk memastikan untuk menggunakan versi bash yang sama yang sedang berjalan:

sudo "$BASH" -c "$(fc -ln -1)"

Perhatikan bahwa karena perintah dieksekusi dalam proses shell terpisah, itu mewarisi variabel lingkungan (hanya yang sudomempertahankan, pikiran), tetapi tidak shell variabel internal. Opsi shell (mis. kshglob) Dan pengaturan lain akan mulai dari default juga.

Perintah yang sama² bekerja di zsh dan ksh, meskipun ATT ksh93 membutuhkan keduanya firstdan lastnomor untuk diteruskan ke fc³ (yang juga bekerja di bash, zsh dan pdksh / mksh):

sudo zsh -c "$(fc -ln -1)"
sudo ksh -c "$(fc -ln -1 -1)"
sudo "$0" -c "$(fc -ln -1 -1)"

Menggunakan $0untuk menunjuk executable dari running shell hanya berfungsi jika shell dipanggil melalui $ PATH dan $ PATH belum berubah, atau melalui path absolut.

Berikut metode lain dalam zsh yang sedikit lebih jelas tetapi lebih lama:

sudo zsh -c $history[$[HISTCMD-1]]

Kata terakhir dari peringatan: sudoadalah untuk perintah yang berpotensi berbahaya. Jangan membuatnya terlalu mudah untuk digunakan!

¹ Ada beberapa spasi putih di awal dan substitusi perintah menghilangkan baris baru di akhir, tetapi sintaksis shell tidak peduli tentang itu.
² Saya tidak berpikir zsh atau ksh memiliki sesuatu seperti bash $BASH; $0hanya berfungsi saat ini merupakan path absolut, atau ketika tidak mengandung garis miring dan jalur pencarian perintah belum berubah.
³ adalah alias untuk di ATT ksh tapi itu sama baiknya. fchist

Gilles 'SANGAT berhenti menjadi jahat'
sumber
9

Jika Anda ingin mengulang perintah yang sama dengan sudo !! setelah melakukan perintah seperti ini:

echo "something">/path/file

Anda menggunakan sintaks ganti global untuk mengingat perintah:

!!:gs/>/|sudo tee -a /

Gunakan spasi setelah parameter -a .

Ini setara dengan sudo !! tetapi membantu Anda melewati batasan sudo untuk <dan>. Karena sudo tidak memungkinkan Anda untuk menggunakan [<,>].


Untuk memotong batasan sudo secara umum untuk pengalihan Anda dapat menggunakannya seperti ini:

echo "something" | sudo tee myfile

perintah tee akan memungkinkan Anda untuk membaca dari input standar dan menulis ke output dan file standar

Jika Anda ingin mengulangi perintah dan menambahkan teks ke file, perintah tee memiliki opsi -a untuk menambahkan. Jadi Anda bisa mengingat perintah dengan

sudo !!

dan teks akan ditambahkan dalam file

contoh:

echo "something" | sudo tee -a /path/file
sudo !!
Boogy
sumber
solusi yang bagus, tapi agak sulit untuk dihafal. Bagaimana saya bisa membuat alias untuk perintah menggunakan !! untuk mengingat perintah terakhir ?
rubo77
apakah yang -abenar - benar dibutuhkan? >akan menimpa file, tee -aakan menambahkan, yang akan>>
rubo77
3

Tampaknya sesederhana sudo sh -c "!!":

$ cd /
$ echo hello > foo
bash: foo: Permission denied
$ sudo sh -c "!!"
sudo sh -c "echo hello > foo"
$ ls -l foo
-rw-r--r-- 1 root root 6 Jun 20 16:21 foo
deltab
sumber
3
Jika perintah yang digunakan mengutip, ini tidak selalu sama. Pertimbangkan echo "foo bar"mana sh -c "echo "foo bar""yang akan dicetak dan foobukan foo bar.
godlygeek
Saya sudo sh -c '!!'malah mencoba jika perintah Anda tetapi itu tidak berhasil baik
rubo77
Lalu bagaimana jika perintah Anda menggunakan tanda kutip tunggal dan ganda? Atau penawaran ganda dan ekspansi variabel? Jika pengguna melakukannya: a=bdan kemudian echo "$a" >filedan kemudian sudo sh -c '!!'itu akan berkembang ke sudo sh -c 'echo $a >file'yang akan mencetak baris kosong, bukan bke file.
godlygeek
Jadi, mungkin ada solusi yang lebih baik?
rubo77
1
Saya tidak berpikir ada solusi yang akan bekerja 100% dari waktu tanpa Anda perlu memodifikasi perintah. Menggunakan sudountuk mendapatkan shell root dan kemudian menyalin dan menempelkan perintah ke dalamnya akan paling dekat, tetapi gagal jika perintah itu diharapkan untuk menggunakan variabel yang ditetapkan di shell non-root Anda. Menggunakan sudo sh -c "!!"berfungsi dengan baik untuk perintah sederhana, tetapi penuh untuk yang kompleks. Saya pikir saran terbaik adalah jangan berharap bahwa ada beberapa perintah yang akan bekerja 100% setiap waktu - pelajari beberapa solusi yang mungkin dan terapkan masing-masing ketika itu paling cocok.
godlygeek