書き込み権限のないファイルへのstdoutのリダイレクト


113

書き込み権限を持たずにファイルを変更しようとすると、エラーが発生します。

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

rootとしてコマンドを実行するため、sudoingは役に立ちませんが、シェルはstdoutのリダイレクトを処理し、とにかくファイルを開きます:

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

ルートとしてシェルを開き、その方法でファイルを操作する以外に、書き込み権限のないファイルにstdoutをリダイレクトする簡単な方法はありますか?

> sudo su
# echo test > /tmp/foo

2
StackOverflowののから同様の質問には回答stackoverflow.com/questions/82256/...
クリスティアンCiupituに

tmpに自分で作成したファイルへのアクセス権をどのように取得できないのですか?umaskのせいですか?
k961

@ k961以前chownは所有者を変更していました。それは単なる例でした
マイケル・ムロゼク

回答:


116

はい、使用しteeます。そうecho test > /tmp/fooなる

echo test | sudo tee /tmp/foo

追加することもできます(>>

echo test | sudo tee -a /tmp/foo

27
Teeは標準出力にも出力されます。内容が画面いっぱいに表示されないようにする場合があります。これを修正するには、次を実行しますecho test | sudo tee /tmp/foo > /dev/null
ショーンJ.ゴフ

ヒアドックでどうやってやるの?
-JohnDoea

26

ファイルの内容をecho>シェルリダイレクト演算子のような)の出力に置き換えます。

echo test | sudo dd of=/tmp/foo

seek1<>Bourneシェル演算子のように)切り捨てずに(異なるオフセットでの出力に使用できますが)ファイルに書き込むには:

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

>>GNU を使用して(などの)ファイルに追加するにはdd

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

参照してください。GNU ddさんconv=excl(と同様、既存のファイルつかう避けるために、set -o noclobberPOSIXシェルでの)とconv=nocreat反対のために(のみ、既存のファイルを更新)。


賢い!これecho test | sudo tee /tmp/foo >/dev/nullにより、出力を破棄する必要が軽減されます。
アダム・カッツ

2
私はそれを取り戻さなければならないかもしれません。この答えの優雅さを削除するあいまいなGNUのみのオプションを使用ddしていない限り、それは信頼できませんiflag=fullblock oflag=fullblock。私は固執しteeます。
アダム・カッツ

5
ddは、不明瞭でないbs = 1で信頼性があります
梅干

2
@umeboshiしかし、あなたが何をしているのかを正確に知るのに十分な経験がある場合にのみ信頼できます。わずかなミスがあったdd場合、For はかなり危険です(言うまでもなく、壊滅的です)。したがって、新しいユーザーの場合は、この方法を安全​​な場所に置くことをお勧めします。tee
構文エラー

1
@AdamKatz、dd of=file単独の場合(count/ skip... なし)、信頼性があります。iflag=fullblockここでddは、入力で読み取ったものを出力に書き込むため、必要ありません。それが完全なブロックでなかったかどうかは関係ありません。
ステファンシャゼラス

12

tee おそらく最良の選択ですが、状況によっては次のようなもので十分かもしれません。

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

1
3つの問題:eval単純な代わりにsh -c; -i、作業ディレクトリを変更します; コマンド全体をルートとして実行します。これにより、コマンドの動作が変更されたり、不必要なリスクが発生する可能性があります。なぜこれが賛成票を獲得したのですか?

4
あなたはそうしませんでしたが、それは誤解を招くものであり、一般的に悪いものであり、おそらく危険ですらあります。

5

私は同意しますが、それ| sudo teeは標準的な方法であり、sed(ここではGNUを想定sed)が機能する場合があります。

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

-iファイルを所定の場所に変更します。1i意味の挿入行の前に1. $a手段を追加し、最後の行の後。

または、xclipboardにコピーします。

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

1
これは古代中国のなぞなぞのように表現されています。これがどうして多くの賛成票を得たのか理解できない。(hrmph
構文エラー

1
@syntaxerror:ごめんなさい、私は英語のネイティブスピーカーではありません。不明な点を指定していただければ、答えを改善することができます。Gertの65の賛成票と比較して、4はそれほど多くの賛成票でもないようです。
ユーザー不明

まあ、私は4にかなり満足するでしょう:-Dあなたの英語は全く悪くありません。それは、ある種の簡潔な技術のオタクの言葉で伝えられているだけです。あなたがコーダーだと思います。お互いのコーダーはそのように完全に自分自身を理解しますが、コーダーでない人はそれが...言われたように表現されていると考えなければなりません。
構文エラー

sed -i実際にファイルを変更するわけではないことに注意しください-一時ファイルを作成し、終了時に名前を変更します。だから、のような何かをすることはできませんtail -f ...元のファイルにして使用して出力を参照してくださいsed -i ...パイプラインが実行されている間
アンドリュー・ヘンレ

@AndrewHenle:はい、サイズが増減する可能性があるため、ほとんどのsed呼び出しの場合がそうであるため、SSDの同じ場所に書き込むこともできません。 。英語を母国語としない人として、誤解されそうにない簡単な表現をお願いできますか?ただ、-i creates a new file of same nameまたはよりコンパクトなものはありますか?私が好きな推測in placeそれが説明するので、i。gnu-sedのマンページでも適切に呼び出さ、長いフラグは--in-placeです。
ユーザー不明

2

私は、同様の問題についての考えを思いついた後、次の解決策を思いつきました。

  • sudo uncatwhere uncatは、標準入力を読み取り、コマンドラインで指定されたファイルに書き込むプログラムですが、uncatまだ作成していません。

  • sudocatsudoedit私がまだ書いていないそのバリアントは、クリーナーsudo catまたはを行いsudo uncatます。

  • またはsudoedit、シェルスクリプトであるEDITOR で使用するこの小さなトリック

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

    これはどちらかとして呼び出すことができる|sudo ./uncat fileか、| EDITOR=./uncat sudoeditそれは興味深い副作用があります。


catコンファイルのリストを受け取り、猫へのファイルのリスト取る必要がありますのでUNCAT、inateを解除コンにinateを。マジックを使用して、各ファイルに入れる量を決定する必要があります。代替名が含まれdogto-fileredirect
ctrl-alt-delor

私がいるuncatときに欲しい理由を考えることはできませんtee
ワイルドカード

1
さて、teestdinをstdoutに書き込むというささいな欠点があります。これは、stdoutをにリダイレクトすることで簡単に軽減され/dev/nullます。他の選択肢にはdd of=/tmp/foo、ステータス情報をstderrに書き込む(別の回答で述べた)およびが含まれcp /dev/stdin /tmp/fooます。
スコット

1

moreutilsパッケージのスポンジを使用します。標準出力に書き込まないという利点があります。

echo test | sudo sponge /tmp/foo

-aオプションを使用して、ファイルを上書きする代わりに追加します。


1
stdoutに書き込まないことの利点がわからない/dev/nullが、問題が発生した場合に出力をリダイレクトすることができます
Michael Mrozek

1
もちろん、/ dev / nullにリダイレクトすることもできますが、リダイレクトを使用せずにコマンドを読み、入力する方が簡単です。stdoutに書き込まないことの利点は、端末がゴミで満たされていないことです。
ホントヴァリレヴェンテ

1
私はリダイレクトをtoしまないためにパッケージをインストールしませんが、私は定期的にスポンジを使用するので、すでにそこにあります。
ホントヴァリレヴェンテ

0

エラーは、シェルが処理を行う順序に起因します。

リダイレクトは、シェルが実行される前に処理されるため、sudo現在作業しているユーザーの権限で実行されます。リダイレクトのターゲットを作成/切り捨てる書き込み権限がないためpermission denied、シェルからエラーが発生します。

解決策は、出力ファイルがsudo、たとえば次のように指定されたIDで作成されることを保証することですtee

$ generate_output | sudo tee target_file
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.