sudoを使用して、書き込み権限のない場所に出力をリダイレクトするにはどうすればよいですか?


881

開発RedHat linuxボックスの1つでsudoアクセス権を与えられましたが、通常は書き込みアクセス権がない場所に出力をリダイレクトする必要がかなりあるようです。

問題は、この不自然な例が機能しないことです。

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

私はただ応答を受け取ります:

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

これを機能させるにはどうすればよいですか?


1
chmod u + w filenameを使用
Szabolcs Dombi

@DombiSzabolcsあなたは私が最初にsudoとしてファイルを作成し、次に自分に許可を与えることを提案していますか?良いアイデア。
ジョナサン

「許可が拒否されるのはなぜですか?」場合によっては、ファイルを作成する必要があるという答えがありますroot(この場合、答えを読むために進みます)が、たいていの場合、自分のように別の場所にファイルを作成する必要があるだけです。
tripleee

1
これらの答えに苦労した後、私は最終的に一時ファイルにリダイレクトし、sudoで宛先に移動することを選択します。
TingQian LI

回答:


1233

への書き込み権限がないシェルによってリダイレクトが実行されているため、コマンドは機能しません/root/test.out。出力のリダイレクトは、sudoによって実行されません

複数の解決策があります:

  • sudoを使用してシェルを実行し、-cオプションを使用してそれにコマンドを与えます。

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • コマンドを使用してスクリプトを作成し、sudoを使用してそのスクリプトを実行します。

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

    を実行しますsudo ls.sh。一時ファイルを作成したくない場合は、Steve Bennettの回答を参照してください。

  • でシェルを起動してsudo -s、コマンドを実行します。

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • 使用sudo tee-cオプションを使用するときにたくさんエスケープする必要がある場合):

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

    Tが画面に出力されないようにするには、リダイレクト先/dev/nullが必要です。追記の代わりに、出力ファイルを上書きする()、使用または(最後のものは固有であるGNUのcoreutilsの)。>>tee -atee --append

2番目、3番目、4番目のソリューションを提供してくれたJdAdam J. Forster、およびJohnathanに感謝します。


1
STDERRとSTDOUTを別々にリダイレクトする方法を説明する素晴らしい答えがあります:stackoverflow.com/questions/692000/… ...基本的にperl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
errant.info

2
シェル化されたコマンドで変数を使用するために「sudo -E ...」を実行する必要があります(これをスクリプトで使用する場合など)。
Urhixidur 2014

3
画面に出力をエコーし​​ても無害な多くの場合、T字出力を/ dev / nullにリダイレクトする必要はおそらくありません。たとえば、通常のコマンドの出力や小さなテキストファイルの内容だけを扱う場合などです。
thomasrutter 2015

105

ここの誰かがちょうどsudoing teeを提案しました:

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

これを使用して、アクセスできないディレクトリにコマンドをリダイレクトすることもできます。これは、teeプログラムが効果的に「ファイルへのエコー」プログラムであり、/ dev / nullへのリダイレクトが、画面への出力も停止して上記の元の不自然な例と同じに保つために機能します。


5
多くの場合、つまり、通常のユーザーにコマンドを実行する権限があり、「のみ」が目的の出力ファイルに書き込めない場合、最初のsudo(つまり、コマンド自体の)が省略される可能性があります
Hagen von Eitzen

81

私が自分で考え出したトリックは

sudo ls -hal /root/ | sudo dd of=/root/test.out

16
sudo ddsudo tee /root/file > /dev/null上記の例よりも優れています!
kristianlm 2013

14
ddは奇妙なあいまいなコマンドではありません。これは、2つのブロックデバイス間でバッファリングして大量のデータをコピーする必要がある場合に使用されます。構文は実際にはかなり単純でdd、コマンド名でof=/root/test.outありdd、出力ファイルが何であるかを伝える引数です。
rhlee、2013

14
@steveあなたがそれが何であるかを学ぶまで、すべては「あいまい」です。出力ファイルof意味し、LinuxとOSXの両方で使用される非常に人気のあるツールです(主にイメージをディスクに書き込むため)。これは確かにきちんとしたトリックです。dd
blockloop

12
ddおそらくteeここと同じくらい便利です。どちらの場合も、元の意図した目的とは少し異なりますが、よく知られており、十分に文書化されている目的で、一般的なよく知られたコマンドを使用しています。一方でdd大量のデータをコピーするのが得意で、それは少量で吸うしません。これには、出力を標準出力にエコーしないという利点もあります。
thomasrutter 2015

26
sudo dd隣り合って単語を入力するときはいつでも、後続の引数が正しいことを非常に確実確認する必要があります(特に、非標準の構文を考慮する場合)。彼らはそれを「ディスク駆逐艦」とは呼ばない...
ali_m

45

問題は、コマンドはの下sudoで実行されますが、リダイレクトはユーザーの下で実行されることです。これはシェルによって行われ、それについてできることはほとんどありません。

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

これを回避する通常の方法は次のとおりです。

  • sudoで呼び出すスクリプトにコマンドをラップします。

    コマンドやログファイルが変更された場合は、スクリプトでこれらを引数として使用できます。例えば:

    sudo log_script command /log/file.txt
    
  • シェルを呼び出し、コマンドラインをパラメーターとして渡します -c

    これは、1回限りの複合コマンドで特に役立ちます。例えば:

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

23

テーマのさらに別のバリエーション:

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

またはもちろん:

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

それらには、sudoまたはsh/ への引数を覚えておく必要がないという(小さな)利点があります。bash


18

T字オプションが望ましい理由を少し明確に

出力を作成するコマンドを実行する適切な権限があると想定して、コマンドの出力をteeにパイプ処理する場合、seeを使用してteeの権限を昇格し、teeに問題のファイルに書き込む(または追加する)ように指示するだけです。

質問の例では、次のことを意味します。

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

より実用的な例をいくつか示します。

# 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

これらの各例では、非特権コマンドの出力を取得し、通常はrootのみが書き込み可能なファイルに書き込みます。これは、質問の元です。

出力を生成するコマンドは昇格された特権で実行されないため、このようにすることをお勧めします。ここでは問題ではないようですechoが、sourceコマンドが完全に信頼されていないスクリプトである場合は重要です。

-aオプションを使用する>>と、ターゲットファイルに(のように>)上書きするのではなく、追加する(のように)ことを追加できます。


申し訳ありませんJS3が、これはすでに(2008年バック)が示唆されていると、二番目に高いの答えの前に座っている:stackoverflow.com/a/82553/6910
ジョナサン・

2
そうです、ジョナサン、これが望ましい選択肢である理由を拡大するために私の答えを更新します。役立つフィードバックをありがとう。
jg3 2013年


11

私がこの問題に取り組む方法は:

ファイルの書き込み/置換が必要な場合:

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

ファイルに追加する必要がある場合:

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

1
これは上記の回答とどのように大きく異なりますか?
ジョナサン

2
これは「実質的に異なる」わけではありませんが、ファイルの置換とファイルへの追加の間の明確な使用法を明確にします。
jamadagni

1
これがチートシートにコピーした答えです。
MortimerCat

5

スクリプトを書くのはどうですか?

ファイル名:myscript

#!/bin/sh

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

# end script

次に、sudoを使用してスクリプトを実行します。

sudo ./myscript

4

私がこのようなことをしなければならないときはいつでも、私はルートになります:

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

それはおそらく最良の方法ではありませんが、機能します。


4

私はこのようにします:

sudo su -c 'ls -hal /root/ > /root/test.out'

2
シェルを明示的に指定する必要がないため、実際には少しクリーンに見えます。
スティーブベネット

1
一つの小さな欠点は、(それが一つの追加のプロセスを実行することです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

死んだ馬を打つことを意味しますが、あまりにも多くの答えは、その使用、ここがあるないでくださいtee、あなたがリダイレクトする必要がある手段、stdout/dev/nullは、画面上のコピーを見たいと思っていない限りは。

より簡単な解決策は、次のように使用することcatです。

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

リダイレクションが引用符の中に置かれ、それを実行しているシェルではsudoなく、によって開始されたシェルによって評価されるようになっていることに注意してください。


これは問題なく動作します。なぜ反対票が1票あったのかわかりません。賛成。
Teemu Leisti 2016年

4
それはほど良くないので、あまり愛されないと思いますsudo bash -c "ls -hal /root > /root/test.out"。Tシャツを使用するとシェルが不要になりますが、猫では不要です。
Nick Russo

2

これはに関する回答に基づいていますtee。物事を簡単にするために、小さなスクリプト(私はそれを呼び出すsuwrite)を書いて、許可/usr/local/bin/+x得て入れました:

#! /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

コードのUSAGEに示されているように、出力をこのスクリプトにパイプし、スーパーユーザーがアクセスできるファイル名を指定するだけで、必要に応じて自動的にパスワードの入力を求められます(これにはが含まれているためsudo)。

echo test | suwrite /root/test.txt

これはの単純なラッパーであるためtee-a追加するTのオプションも受け入れ、同時に複数のファイルへの書き込みもサポートすることに注意してください。

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

また/dev/、このページのコメントの1つで言及された懸念事項であった、デバイスへの書き込みに対する単純な保護もいくつかあります。


1

たぶんあなたはいくつかのプログラム/パスだけにsudoアクセスを与えられましたか?それからあなたが望むことをする方法はありません。(あなたがどうにかしてそれをハックしない限り)

そうでない場合は、おそらくbashスクリプトを記述できます。

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

ctrl+を押すd

chmod a+x myscript.sh
sudo myscript.sh

お役に立てば幸いです。


1
sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  

1
sudoとにかく持っている場合atは、役に立ちませんか必要ではありません。sudo sh -c 'echo test >/tmp/test.out'同じことをはるかに効率的かつエレガントに実行します(ただし、おそらくrootその特権を必要としないものを実行しているという欠点があります。一般的に、特権コマンドはできるだけ避けてください)。
tripleee
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.