Mengarahkan stdout ke file yang tidak memiliki izin tulis untuk Anda

113

Ketika Anda mencoba untuk memodifikasi file tanpa izin tertulis di dalamnya, Anda mendapatkan kesalahan:

> touch /tmp/foo && sudo chown root /tmp/foo
> echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Sudoing tidak membantu, karena menjalankan perintah sebagai root, tetapi shell menangani pengalihan stdout dan membuka file seperti Anda:

> sudo echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Apakah ada cara mudah untuk mengarahkan stdout ke file yang Anda tidak punya izin untuk menulis, selain membuka shell sebagai root dan memanipulasi file dengan cara itu?

> sudo su
# echo test > /tmp/foo
Michael Mrozek
sumber
2
Jawab untuk pertanyaan serupa dari StackOverflow stackoverflow.com/questions/82256/…
Cristian Ciupitu
bagaimana bisa Anda tidak memiliki izin untuk file yang Anda buat sendiri di tmp? apakah karena umask?
k961
@ k961 Saya dulu chownmengganti pemilik; itu hanya sebuah contoh
Michael Mrozek

Jawaban:

116

Ya, menggunakan tee. Jadi echo test > /tmp/foomenjadi

echo test | sudo tee /tmp/foo

Anda juga dapat menambahkan ( >>)

echo test | sudo tee -a /tmp/foo
Gert
sumber
27
Tee juga akan keluar ke stdout; terkadang Anda tidak ingin konten mengisi layar. Untuk memperbaikinya, lakukanecho test | sudo tee /tmp/foo > /dev/null
Shawn J. Goff
Bagaimana Anda akan melakukannya dengan heredoc?
JohnDoea
26

Untuk mengganti konten file dengan output echo(seperti >operator pengalihan shell).

echo test | sudo dd of=/tmp/foo

Untuk menulis ke dalam file (di awal, meskipun Anda dapat menggunakan seekuntuk output pada offset yang berbeda) tanpa memotong (seperti 1<>operator shell Bourne):

echo test | sudo dd of=/tmp/foo conv=notrunc

Untuk menambahkan file (seperti >>), dengan GNU dd:

echo test | sudo dd of=/tmp/foo oflag=append conv=notrunc

Lihat juga GNU dd's conv=excluntuk menghindari clobbering file yang ada (seperti dengan set -o noclobberdi kerang POSIX) dan conv=nocreatuntuk berlawanan (hanya memperbarui file yang ada).

Chris Jepeway
sumber
pintar! ini mengurangi kebutuhan yang harus dilakukan echo test | sudo tee /tmp/foo >/dev/nulluntuk membuang output.
Adam Katz
2
Saya mungkin harus mengambilnya kembali; ddtidak dapat diandalkan untuk itu kecuali Anda menggunakan opsi khusus GNU yang tidak jelas iflag=fullblock oflag=fullblock, yang menghapus keanggunan jawaban ini. Saya akan tetap dengan tee.
Adam Katz
5
dd dapat diandalkan dengan bs tidak jelas = 1
umeboshi
2
@umeboshi Tapi hanya dapat diandalkan jika Anda cukup berpengalaman untuk tahu persis apa yang Anda lakukan. Sebab ddbisa sangat berbahaya (jika tidak dikatakan: menghancurkan) jika hanya sedikit kesalahan dibuat. Jadi untuk pengguna baru, saya lebih suka merekomendasikan teemetode ini untuk berada di pantai yang aman.
syntaxerror
1
@AdamKatz, dalam kasus dd of=filesendirian (tanpa count/ skip...), itu dapat diandalkan. iflag=fullblocktidak diperlukan karena di sini ddmenulis tentang keluaran apa yang telah dibaca pada input. Tidak masalah jika itu bukan blok penuh.
Stéphane Chazelas
12

tee mungkin pilihan terbaik, tetapi tergantung pada situasi Anda sesuatu seperti ini mungkin cukup:

sudo sh -c 'echo test > /tmp/foo'
phhehehe
sumber
1
3 masalah: evalbukannya sederhana sh -c; -i, yang akan mengubah dir kerja Anda; menjalankan seluruh perintah sebagai root, yang dapat mengubah perilaku itu atau mungkin menimbulkan risiko yang tidak perlu. mengapa ini pernah mendapat dukungan?
4
Anda tidak melakukannya, tetapi itu menyesatkan, umumnya buruk dan bahkan mungkin berbahaya.
5

Sementara saya setuju, itu | sudo teeadalah cara kanonik, kadang-kadang sed (di sini dengan asumsi GNU sed) dapat bekerja:

cat sudotest 
line 1

sudo sed -i '1iitest' sudotest && cat sudotest 
itest
line 1

sudo sed -i '$aatest' sudotest && cat sudotest 
itest
line 1
atest

-imemodifikasi file di tempat. 1iberarti menyisipkan sebelum baris 1. $aberarti menambahkan setelah baris terakhir.

Atau salin ke xclipboard:

somecommand | xclip
sudo gedit sudotest
move cursor to desired place, click middle mouse button to insert, save
Pengguna tidak diketahui
sumber
1
Ini ditulis seperti teka-teki Cina Kuno. Tidak bisa mengerti bagaimana ini mendapat begitu banyak upvotes. ( hrmph )
syntaxerror
1
@syntaxerror: Pak, maaf, saya bukan penutur asli bahasa Inggris. Jika Anda menentukan apa yang tidak jelas bagi Anda, saya dapat mencoba meningkatkan jawaban saya. Dibandingkan dengan 65 upvotes untuk Gert, 4 sepertinya juga tidak banyak upvotes, bukan begitu?
pengguna tidak diketahui
Yah saya akan cukup puas dengan 4 :-D Bahasa Inggris Anda tidak buruk sama sekali. Itu hanya kata-kata dalam semacam nerdspeak techie singkat. Saya kira Anda seorang pembuat kode. Coder di antara satu sama lain akan memahami diri mereka dengan sempurna seperti itu, tetapi non-coder harus berpikir itu seperti kata ... seperti dikatakan.
syntaxerror
Catatan yang sed -itidak benar-benar memodifikasi file di tempat - itu membuat file sementara dan mengganti nama saat keluar. Jadi Anda tidak akan dapat melakukan sesuatu seperti tail -f ...pada file asli dan melihat output menggunakan sed -i ...saat pipa sedang berjalan
Andrew Henle
@AndrewHenle: Ya, karena ukurannya mungkin bertambah atau menyusut, dan karena itu mungkin terjadi pada kebanyakan doa sed, dan Anda bahkan tidak bisa - afaik - menulis ke lokasi yang sama dengan SSD, itu hanya operasi 'in place' semu yang semu . Sebagai penutur bahasa Inggris yang bukan penutur asli, bolehkah saya meminta ungkapan singkat, yang sepertinya tidak disalahartikan? Hanya -i creates a new file of same nameatau ada sesuatu yang lebih kompak? Saya kira saya suka in place, karena itu menjelaskan i. Manual gnu-sed menyebutnya di tempat juga dan bendera panjangnya --in-place.
pengguna tidak dikenal
2

Saya telah menendang-nebak ide-ide pikiran saya untuk masalah yang sama, dan muncul dengan solusi berikut:

  • sudo uncatdi mana uncatada program yang membaca input standar dan menulisnya ke file bernama pada baris perintah, tapi saya belum menulis uncat.

  • sudocatvarian sudoedityang belum saya tulis yang melakukan pembersih sudo catatau sudo uncat.

  • atau trik kecil ini menggunakan sudoeditdengan EDITOR yang merupakan skrip shell

    #!/bin/sh
    # uncat
    cat > "$1"
    

    yang dapat dipanggil sebagai salah satu |sudo ./uncat fileatau | EDITOR=./uncat sudoedittetapi yang memiliki efek samping yang menarik.

Hildred
sumber
catmengambil daftar file ke con cat inate, oleh karena itu uncat harus mengambil daftar file ke un con cat inate. Itu harus menggunakan sihir untuk memutuskan berapa banyak untuk dimasukkan ke dalam setiap file. Nama alternatif termasuk dog, to-file, redirect.
ctrl-alt-delor
Saya tidak bisa memikirkan alasan mengapa saya ingin uncatketika saya punya tee.
Wildcard
1
Nah, teememiliki kelemahan sepele yang ia tulis stdin ke stdout - yang diremehkan sepele dengan mengarahkan stdout ke /dev/null. Alternatif lain termasuk dd of=/tmp/foo(disebutkan dalam jawaban lain), yang menulis informasi status ke stderr, dan cp /dev/stdin /tmp/foo.
Scott
1

Gunakan spons dari paket moreutils. Ini memiliki keuntungan bahwa ia tidak menulis ke stdout.

echo test | sudo sponge /tmp/foo

Gunakan opsi -a untuk menambahkan file daripada menimpanya.

Hontvári Levente
sumber
1
Saya tidak yakin apa untungnya tidak menulis ke stdout hadiah, tetapi Anda bisa mengarahkan output ke /dev/nulljika itu masalah
Michael Mrozek
1
Tentu saja saya bisa mengarahkan ulang ke / dev / null, tetapi perintahnya lebih mudah dibaca dan diketik tanpa pengalihan. Keuntungan dari tidak menulis ke stdout adalah terminal saya tidak dipenuhi dengan sampah.
Hontvári Levente
1
Saya tidak akan menginstal paket untuk cadangan pengalihan, tetapi saya secara teratur menggunakan spons, jadi sudah ada di sana.
Hontvári Levente
0

Kesalahan berasal dari urutan shell melakukan sesuatu.

Pengalihan ditangani bahkan sebelum shell mengeksekusi sudo, dan karena itu dilakukan dengan izin dari pengguna yang saat ini Anda bekerja. Karena Anda tidak memiliki izin menulis untuk membuat / memotong target pengalihan, Anda mendapatkan permission deniedkesalahan dari shell.

Solusinya adalah untuk menjamin bahwa file keluaran dibuat di bawah identitas yang diberikan kepada Anda oleh sudo, misalnya dengan tee:

$ generate_output | sudo tee target_file
Kusalananda
sumber