Bagaimana cara menggunakan sudo untuk mengarahkan output ke lokasi yang saya tidak punya izin untuk menulis?

881

Saya telah diberikan akses sudo pada salah satu kotak pengembangan RedHat linux kami, dan saya sepertinya mendapati diri saya cukup sering perlu mengarahkan ulang output ke lokasi yang saya biasanya tidak memiliki akses tulis.

Masalahnya adalah, contoh buatan ini tidak berfungsi:

sudo ls -hal /root/ > /root/test.out

Saya baru saja menerima tanggapan:

-bash: /root/test.out: Permission denied

Bagaimana saya bisa membuatnya bekerja?

Jonathan
sumber
1
gunakan chmod u + w filename
Szabolcs Dombi
@DombiSzabolcs Anda menyarankan agar saya membuat file sebagai sudo terlebih dahulu, lalu beri izin pada diri sendiri? Ide bagus.
Jonathan
Dalam banyak situasi Anda berakhir di sini karena Anda bertanya "mengapa saya mendapatkan Izin?" Terkadang jawabannya adalah Anda memang perlu membuat file seperti root(dalam hal ini lanjutkan membaca jawaban) tetapi sangat sering, Anda hanya perlu membuat file di tempat lain, seperti diri Anda sendiri.
tripleee
1
Setelah berjuang dengan jawaban ini saya akhirnya memilih untuk mengarahkan ulang ke file temp dan sudo memindahkannya ke tujuan.
TingQian LI
Lihat juga stackoverflow.com/questions/84882/…
Nate Eldredge

Jawaban:

1233

Perintah Anda tidak berfungsi karena pengalihan dilakukan oleh shell Anda yang tidak memiliki izin untuk menulis /root/test.out. Pengalihan output tidak dilakukan oleh sudo.

Ada beberapa solusi:

  • Jalankan shell dengan sudo dan berikan perintah padanya dengan menggunakan -copsi:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • Buat skrip dengan perintah Anda dan jalankan skrip itu dengan sudo:

    #!/bin/sh
    ls -hal /root/ > /root/test.out
    

    Lari sudo ls.sh. Lihat jawaban Steve Bennett jika Anda tidak ingin membuat file sementara.

  • Luncurkan shell dengan sudo -slalu jalankan perintah Anda:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • Gunakan sudo tee(jika Anda harus banyak melarikan diri saat menggunakan -copsi):

    sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
    

    Redirect ke /dev/nulldiperlukan untuk menghentikan tee agar tidak keluar ke layar. Untuk menambahkan alih-alih menimpa file output ( >>), gunakan tee -aatau tee --append(yang terakhir adalah khusus untuk GNU coreutils ).

Terima kasih kepada Jd , Adam J. Forster dan Johnathan untuk solusi kedua, ketiga dan keempat.

Cristian Ciupitu
sumber
1
Ada jawaban yang bagus yang memberi tahu Anda cara mengarahkan STDERR dan STDOUT secara terpisah di sini: stackoverflow.com/questions/692000/… ... pada dasarnyaperl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
errant.info
2
Anda akan ingin melakukan 'sudo -E ...' untuk menggunakan variabel dalam perintah shelled out (saat menggunakan ini dalam skrip, misalnya).
Urhixidur
3
Mengarahkan output tee ke / dev / null mungkin tidak diperlukan dalam banyak kasus di mana gema output ke layar tidak berbahaya. Misalnya, ketika berhadapan dengan output dari perintah biasa atau isi file teks kecil.
thomasrutter
105

Seseorang di sini baru saja menyarankan sudoing tee:

sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null

Ini juga dapat digunakan untuk mengarahkan ulang perintah apa pun, ke direktori yang Anda tidak memiliki akses. Ini bekerja karena program tee secara efektif merupakan program "gema ke file", dan redirect ke / dev / null adalah untuk menghentikannya juga menampilkan ke layar agar tetap sama seperti contoh asli yang dibuat di atas.

Jonathan
sumber
5
Dalam banyak kasus, yaitu jika pengguna normal memiliki prmisi untuk melakukan perintah dan "hanya" tidak dapat menulis ke file output yang diinginkan, yang pertama sudo(yaitu, untuk perintah itu sendiri) mungkin dihilangkan
Hagen von Eitzen
81

Trik yang saya temukan sendiri adalah

sudo ls -hal /root/ | sudo dd of=/root/test.out
rhlee
sumber
16
sudo ddlebih baik dari sudo tee /root/file > /dev/nullcontoh di atas!
kristianlm
14
dd bukan perintah aneh yang aneh. Ini digunakan kapan pun Anda perlu menyalin data dalam jumlah besar dengan buffering antara dua perangkat blok. Sintaks sebenarnya cukup sederhana, ddadalah nama perintah, of=/root/test.outadalah argumen yang memberi tahu ddapa File Output.
rhlee
14
@steve Semuanya adalah 'tidak jelas' sampai Anda mengetahui apa itu. ofberarti file output dan ddmerupakan alat yang sangat populer digunakan di Linux dan OSX (kebanyakan untuk menulis gambar ke disk). Ini trik yang pasti.
blockloop
12
ddmungkin sama bermanfaatnya seperti di teesini. Dalam kedua kasus Anda menggunakan perintah umum yang terkenal untuk tujuan yang, meskipun sedikit berbeda dengan tujuan semula, masih terkenal dan didokumentasikan dengan baik. Meskipun ddpandai menyalin data dalam jumlah besar, itu tidak payah dengan jumlah kecil. Ini memiliki manfaat di sini tidak menggema output ke output standar juga.
thomasrutter
26
Setiap kali Anda mengetik kata-kata di sudo ddsamping satu sama lain, Anda ingin membuat sangat, sangat yakin bahwa argumen yang mengikuti sudah benar (terutama mengingat sintaksinya yang tidak standar). Mereka tidak menyebutnya "perusak disk" tanpa
bayaran
45

Masalahnya adalah bahwa perintah dijalankan di bawah sudo, tetapi pengalihan dijalankan di bawah pengguna Anda. Ini dilakukan oleh shell dan ada sangat sedikit yang dapat Anda lakukan.

sudo command > /some/file.log
`-----v-----'`-------v-------'
   command       redirection

Cara biasa untuk melewati ini adalah:

  • Bungkus perintah dalam skrip yang Anda panggil dengan sudo.

    Jika perintah dan / atau file log berubah, Anda dapat membuat skrip menganggapnya sebagai argumen. Sebagai contoh:

    sudo log_script command /log/file.txt
    
  • Panggil shell dan lulus baris perintah sebagai parameter dengan -c

    Ini sangat berguna untuk perintah gabungan. Sebagai contoh:

    sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    
dsm
sumber
23

Variasi lain pada tema:

sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF

Atau tentu saja:

echo 'ls -hal /root/ > /root/test.out' | sudo bash

Mereka memiliki (kecil) keuntungan yang Anda tidak perlu mengingat argumen apapun untuk sudoatau sh/bash

Steve Bennett
sumber
18

Klarifikasi sedikit tentang mengapa opsi tee lebih disukai

Dengan asumsi Anda memiliki izin yang sesuai untuk mengeksekusi perintah yang menciptakan output, jika Anda mengirimkan output dari perintah Anda ke tee, Anda hanya perlu meninggikan hak istimewa tee dengan sudo dan tee langsung untuk menulis (atau menambahkan) ke file yang dimaksud.

dalam contoh yang diberikan dalam pertanyaan yang berarti:

ls -hal /root/ | sudo tee /root/test.out

untuk beberapa contoh yang lebih praktis:

# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts

# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4

Dalam setiap contoh ini, Anda mengambil output dari perintah yang tidak diistimewakan dan menulis ke file yang biasanya hanya dapat ditulis oleh root, yang merupakan asal dari pertanyaan Anda.

Ini adalah ide yang baik untuk melakukannya dengan cara ini karena perintah yang menghasilkan output tidak dieksekusi dengan privilege yang ditinggikan. Tampaknya tidak masalah di sini, echotetapi ketika perintah sumber adalah sebuah skrip yang tidak Anda percayai sepenuhnya, itu penting.

Catatan Anda dapat menggunakan opsi -a untuk tee untuk menambahkan append (suka >>) ke file target daripada menimpanya (seperti >).

jg3
sumber
Maaf js3, tetapi ini sudah disarankan (kembali pada 2008) dan duduk di jawaban tertinggi kedua: stackoverflow.com/a/82553/6910
Jonathan
2
Anda benar, Jonathan, saya akan memperbarui jawaban saya untuk memperluas alasan mengapa ini adalah pilihan yang lebih disukai. Terima kasih atas umpan balik yang bermanfaat.
jg3
17

Buat sudo run shell, seperti ini:

sudo sh -c "echo foo > ~root/out"
Penfold
sumber
11

Cara saya membahas masalah ini adalah:

Jika Anda perlu menulis / mengganti file:

echo "some text" | sudo tee /path/to/file

Jika Anda perlu menambahkan file:

echo "some text" | sudo tee -a /path/to/file
Nikola Petkanski
sumber
1
Bagaimana perbedaannya dengan jawaban di atas?
Jonathan
2
Ini tidak "berbeda secara substansial" tetapi ini menjelaskan penggunaan khusus antara mengganti dan menambahkan file.
jamadagni
1
Ini adalah jawaban yang saya salin ke lembar contekan saya.
MortimerCat
5

Bagaimana dengan menulis naskah?

Nama file: myscript

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

Kemudian gunakan sudo untuk menjalankan skrip:

sudo ./myscript

sumber
4

Setiap kali saya harus melakukan sesuatu seperti ini, saya menjadi root:

# sudo -s
# ls -hal /root/ > /root/test.out
# exit

Ini mungkin bukan cara terbaik, tetapi berhasil.

Adam J. Forster
sumber
4

Saya akan melakukannya dengan cara ini:

sudo su -c 'ls -hal /root/ > /root/test.out'
fardjad
sumber
2
Itu sebenarnya tampak sedikit lebih bersih, karena Anda tidak perlu secara eksplisit menentukan shell.
Steve Bennett
1
Satu kekurangan kecil adalah menjalankan satu proses tambahan ( su): $ sudo su -c 'pstree -sp $$ >/dev/fd/1' init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411)
pabouk
3

Tidak bermaksud untuk mengalahkan kuda mati, tetapi ada terlalu banyak jawaban di sini bahwa penggunaan tee, yang berarti Anda harus mengarahkan stdoutke /dev/nullkecuali jika Anda ingin melihat salinan di layar.

Solusi yang lebih sederhana adalah dengan menggunakan catseperti ini:

sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"

Perhatikan bagaimana pengalihan dimasukkan ke dalam tanda kutip sehingga dievaluasi oleh shell yang dimulai dengan sudobukannya yang menjalankannya.

haridsv
sumber
Ini berfungsi dengan baik. Saya tidak mengerti mengapa itu memiliki satu suara negatif. Terpilih.
Teemu Leisti
4
Saya pikir itu tidak mendapatkan banyak cinta karena itu tidak jauh lebih baik daripada sudo bash -c "ls -hal /root > /root/test.out". Menggunakan tee tidak memerlukan shell, sedangkan kucing tidak.
Nick Russo
2

Ini didasarkan pada jawaban yang melibatkan tee. Untuk mempermudah, saya menulis skrip kecil (saya menyebutnya suwrite) dan memasukkannya /usr/local/bin/dengan +xizin:

#! /bin/sh
if [ $# = 0 ] ; then
    echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
    exit 1
fi
for arg in "$@" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg’. Will exit."
        exit 2
    fi
done
sudo tee "$@" > /dev/null

Seperti yang ditunjukkan dalam USAGE dalam kode, yang harus Anda lakukan adalah menyalurkan output ke skrip ini diikuti oleh nama file yang dapat diakses oleh superuser yang diinginkan dan secara otomatis akan meminta kata sandi Anda jika diperlukan (karena sudah termasuk sudo).

echo test | suwrite /root/test.txt

Perhatikan bahwa karena ini adalah pembungkus sederhana untuk tee, itu juga akan menerima -aopsi tee untuk menambahkan, dan juga mendukung penulisan ke beberapa file pada saat yang sama.

echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt

Ini juga memiliki beberapa perlindungan sederhana terhadap penulisan ke /dev/perangkat yang menjadi perhatian yang disebutkan dalam salah satu komentar di halaman ini.

jamadagni
sumber
1

Mungkin Anda diberi akses sudo ke hanya beberapa program / jalur? Maka tidak ada cara untuk melakukan apa yang Anda inginkan. (kecuali Anda akan meretasnya entah bagaimana)

Jika bukan itu masalahnya, mungkin Anda bisa menulis skrip bash:

cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out 

Tekan ctrl+ d:

chmod a+x myscript.sh
sudo myscript.sh

Semoga ini bisa membantu.

pengguna15453
sumber
1
sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  
pengguna8648126
sumber
1
Jika Anda punya sudo, attidak berguna atau tidak perlu. sudo sh -c 'echo test >/tmp/test.out'melakukan hal yang sama dengan jauh lebih efisien dan elegan (tetapi masih menderita cacat karena Anda mungkin menjalankan hal-hal rootyang tidak memerlukan hak istimewa itu; Anda biasanya harus menghindari perintah istimewa ketika Anda bisa).
tripleee