【Bash】リダイレクトやパイプの権限
経緯
bash で実行ユーザーが write 権限を持たないファイルに sudo cat
コマンドで書き込もうとしてエラーにあたりました。リダイレクトとパイプについて少し知識が深まったのでメモを残します。
$ whoami
testuser
$ ls -l ./testfile
-rw------- 1 otheruser othergroup 13 Apr 7 20:23 ./testfile
$ sudo cat ./testfile
this is test
$ sudo cat << EOF > ./testfile
> abc
> EOF
-bash: ./testfile: Permission denied
$ sudo cat ./testfile
this is test
リダイレクトへの理解が浅く、 Permission denied されました。
ここでは cat
は標準入力から入力を受け付けて標準出力に出力しているだけなので特権を必要としていません。必要としているのは他のユーザー otheruser
が所有者になっているファイル ./testfile
に書き込もうとしているリダイレクト>
でした。
原因
リダイレクト >
はコマンドではなくシェルの機能[1]なのでシェルの実行ユーザーの権限を持ちます。この権限が出力先ファイルの書き込み権限を満たさないといけません。パイプ |
も同じです。
間違ったパターン
sudo cat
パターン
上記経緯のパターン
$ whoami
testuser
$ ls -l ./testfile
-rw------- 1 otheruser othergroup 13 Apr 7 20:23 ./testfile
$ sudo cat ./testfile
this is test
$ sudo cat << EOF > ./testfile
> abc
> EOF
-bash: ./testfile: Permission denied
$ sudo cat ./testfile
this is test
cat
が必要とする権限は入力となるファイルの read 権限だけなので、 cat に対して sudo は必要なく、ここで Permission denied されているのはリダイレクトです。つまり原因はリダイレクト (シェル) がファイルへの write 権限を持っていないことでした。
正解パターン
sudo sh -c パターン
sudo sh -c
を使うパターン。 sh
は bash
でも大丈夫です[2]。
$ sudo sh -c "cat > ./testfile" << EOF
> abc
> EOF
$ sudo cat ./testfile
abc
sudo tee パターン
リダイレクトの代わりに パイプ -> sudo tee
経由で目的のファイルに渡すパターン。tee
が sudo
権限を持つので ./testfile
に書き込むことができます。tee
から標準出力への出力は /dev/null
に捨てます。
$ sudo tee ./testfile > /dev/null << EOF
> xyz
> EOF
$ sudo cat ./testfile
xyz
最後に
sudo sh -c
パターンが一番わかりやすいと感じました。よりよい解決方法などがありましたらコメントで教えてもらえると嬉しいです。
参考
sudo(8) - Linux manual page
Redirections - Bash Reference Manual
LICENSE
本記事は CC-BY-SA-4.0 ライセンスの下に公開しています。
このライセンス文の日本語版は下記ページをご確認ください。
Discussion