Stdout'u, üzerinde yazma izniniz olmayan bir dosyaya yönlendirmek


113

Üzerinde dosya yazma izni olmayan bir dosyayı değiştirmeye çalıştığınızda hata alırsınız:

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

Sudoing komutu komutu root olarak çalıştığı için yapmaz, ancak kabuk stdout'u yönlendirir ve yine de dosyayı açar:

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

Stdout'u yazma izniniz olmayan bir dosyaya yeniden yönlendirmenin kolay bir yolu var mı? Bir kabuğu kök olarak açmak ve dosyayı bu şekilde değiştirmek dışında?

> sudo su
# echo test > /tmp/foo

2
Benzer bir sorunun
yanıtını

tmp'de oluşturduğunuz bir dosyaya nasıl izin veremezsiniz? Umask mı?
k961,

@ k961 chownSahibini değiştirmek için kullanılır ; sadece bir örnekti
Michael Mrozek

Yanıtlar:


116

Evet, kullanarak tee. Öyle echo test > /tmp/fooolur

echo test | sudo tee /tmp/foo

Ayrıca ekleyebilir ( >>)

echo test | sudo tee -a /tmp/foo

27
Tee ayrıca stdout'a da çıkacak; Bazen içeriğin ekranı doldurmasını istemezsiniz. Bunu düzeltmek için, yapınecho test | sudo tee /tmp/foo > /dev/null
Shawn J. Goff,

Heredoc ile nasıl yapacaksın?
JohnDoea

26

Dosyanın içeriğini çıktıyla değiştirmek için echo( >kabuk yönlendirme operatörü gibi).

echo test | sudo dd of=/tmp/foo

Dosyaya yazmak için (başlangıçta, seekfarklı ofsetlerde çıktı almak için kullanabilirsiniz ) kesmeden ( 1<>Bourne kabuğu operatörü gibi):

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

>>GNU ile dosyaya (gibi ) eklemek için dd:

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

Ayrıca bkz GNU dd'ın conv=excl(olduğu gibi varolan bir dosyayı clobbering önlemek için set -o noclobberPOSIX kabuklarda) ve conv=nocreatkarşıt için (sadece varolan bir dosyayı güncelleştirmek).


zeki! bu echo test | sudo tee /tmp/foo >/dev/null, çıkışı atmak için yapılması gerekenleri azaltır .
Adam Katz

2
Bunu geri almak zorunda kalabilirim; bu cevabın zerafetini ortadan kaldıran, yalnızca gizli GNU seçeneklerini kullanmadığınız sürece dd, bunun için güvenilmeziflag=fullblock oflag=fullblock . Ben buna sadık kalacağım tee.
Adam Katz

5
dd,
gizlenmeyen

2
@umeboshi Ancak, yalnızca ne yaptığınızı tam olarak bilecek kadar deneyimliyseniz güvenilirdir. Çünkü ddçok ufak bir hata yapılmışsa (eğer söylemezseniz: yıkıcı) oldukça tehlikeli olabilir . Bu nedenle, yeni kullanıcılar teeiçin, güvenli sahillerde olma yöntemini tavsiye ederim .
sözdizimi,

1
@AdamKatz, dd of=filetek başına ( count/ skip... olmadan ), güvenilirdir. iflag=fullblockgerekli değildir çünkü burada ddçıktıda girdiyi okuduğunu yazar. Dolu bloklar olmaması önemli değil.
Stéphane Chazelas

12

tee muhtemelen en iyi seçimdir, ancak durumunuza bağlı olarak böyle bir şey yeterli olabilir:

sudo sh -c 'echo test > /tmp/foo'

1
3 problem: evalbasit yerine sh -c; -i, çalışma direktörünüzü değiştirecek; Komutun tamamını root olarak çalıştırmak, davranışını değiştirebilir veya gereksiz bir risk oluşturabilir. bu neden hiç bir onur kazandı?

4
yapmadın, ama yanıltıcı, genellikle kötü ve hatta tehlikeli.

5

Kabul etmeme rağmen, bu | sudo teekurallı yol, bazen sed (burada GNU varsayarsak sed) işe yarayabilir:

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

-idosyayı yerinde değiştirir. 1ianlamı eklemek satırdan önce 1. $aaraçlarını ekleme son satırdan sonra.

Veya xclipboard'a kopyalayın:

somecommand | xclip
sudo gedit sudotest
move cursor to desired place, click middle mouse button to insert, save

1
Bu Antik Çin bilmecesi gibi ifade edilir. Bunun nasıl bu kadar çok oy aldığını anlayamıyorum. ( hrmph )
sözdizimi,

1
@syntaxerror: Efendim, özür dilerim, ana dili İngilizce değil. Sizin için belirsiz olanı belirtirseniz cevabımı iyileştirmeyi deneyebilirim. Gert için 65, 4 oy ile karşılaştırıldığında, 4 de öyle değil, öyle değil mi?
kullanıcı bilinmeyen

Şey 4 :-D'den oldukça memnun olurum. İngilizcen hiç de fena değil. Sadece bir çeşit vecize techie nerdspeak ile ifade edildi. Bir kodlayıcı olduğunu tahmin etmeliyim. Birbirleri arasındaki kodlayıcılar kendilerini bu şekilde mükemmel bir şekilde anlayacaklardır, ancak kodlayıcı olmayan bir kişinin dediği gibi ... ifade edildiğini düşünmesi gerekir.
sözdizimi,

sed -iYerinde dosyayı gerçekten değiştirmediğini unutmayın - geçici bir dosya oluşturur ve çıkarken yeniden adlandırır. Böylece tail -f ..., orijinal dosyadaki gibi bir şey yapamazsınız sed -i ...ve boru hattı çalışırken çıktıyı görürsünüz
Andrew Henle

@AndrewHenle: Evet, çünkü boyut arttırılabilir veya daraltılabilir ve bu nedenle çoğu zorlu istilalar için muhtemelen geçerli olduğundan ve hatta - afaik - SSD'lerde aynı yere yazamazsınız, sadece 'yerinde' işlemi sözdedir . Ana dili İngilizce olmayan bir konuşmacı olarak, yanlış anlaşılmayan kısa bir ifade isteyebilir miyim? Sadece -i creates a new file of same nameya da daha küçük bir şey mi var? Sanırım hoşuma gidiyor in place, çünkü açıklıyor i. Gnu-sed manpage onu da yerinde çağırıyor ve uzun bayrak --in-place.
kullanıcı bilinmeyen,

2

Benzer bir sorun için fikrimin arkasında tekmeliyorum ve aşağıdaki çözümleri buldum:

  • sudo uncatnerede uncatstandart girdi okur ve komut satırında adlı dosyaya yazar bir programdır, ama ben yazmadım uncathenüz.

  • sudocatvaryant sudoeditben yazmadım bu henüz o daha temiz yapar sudo catveya sudo uncat.

  • veya bu küçük numara sudoeditbir kabuk komut dosyası olan bir EDITOR ile kullanma

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

    bunlar ya |sudo ./uncat fileda gibi çağrılabilir ya da | EDITOR=./uncat sudoeditilginç yan etkilere sahiptir.


catdolandırmaya dosyaların bir listesini alır kedi için dosyaların bir listesini almalı nedenle UNCAT'ın, rafinat un con kedi için rafinat. Her dosyaya ne kadar koyulacağına karar vermek için sihir kullanmak zorunda kalacaktı. Alternatif isim dahil dog, to-file, redirect.
ctrl-alt-delor

Ben istediğim neden herhangi bir nedenle düşünemiyorum uncatben varken tee.
Joker

1
Eh, teestdout'unu stdout'una yazdığı önemsiz dezavantajı var - stdout'u yeniden yönlendirerek önemsizce azaltıldı /dev/null. Diğer alternatifler arasında dd of=/tmp/foodurum bilgisini stderr'e yazan (başka bir cevabın içinde belirtilen) bulunur cp /dev/stdin /tmp/foo.
Scott,

1

Moreutils paketinden sünger kullanın. Stdout'a yazmadığı bir avantaja sahiptir.

echo test | sudo sponge /tmp/foo

Üzerine yazmak yerine bir dosyaya eklemek için -a seçeneğini kullanın.


1
Stdout'a yazmadığın avantajın ne olduğundan emin değilim, ama /dev/nullbir sorun olsaydı çıktıyı yeniden yönlendirebilirdin
Michael Mrozek

1
Elbette / dev / null dizinine yönlendirebilirim, ancak komut yeniden yönlendirmeden okunması ve yazılması daha kolaydır. Stdout'a yazmamanın avantajı, terminalimin çöple dolu olmamasıdır.
Hontvári Levente

1
Yeniden yönlendirmeyi ayırmak için bir paket yüklemezdim, ancak düzenli olarak sünger kullanıyorum, bu yüzden zaten orada.
Hontvári Levente

0

Hata, kabuğun iş yaptığı sırada ortaya çıkar.

Yeniden yönlendirme, kabuk bile yürütülmeden önce gerçekleştirilir sudove bu nedenle şu anda çalıştığınız kullanıcının izinleri ile yapılır. Yeniden yönlendirmenin hedefini oluşturmak / kesmek için yazma izniniz olmadığından permission denied, kabuktan bir hata alırsınız .

Çözüm, çıktı dosyasının size verilen kimlik altında oluşturulduğunu garanti etmektir sudo, örneğin tee:

$ generate_output | sudo tee target_file
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.