🍣

【Bash】リダイレクトやパイプの権限

2023/04/07に公開

経緯

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 を使うパターン。 shbash でも大丈夫です[2]

$ sudo sh -c "cat > ./testfile" << EOF
> abc
> EOF
$ sudo cat ./testfile
abc

sudo tee パターン

リダイレクトの代わりに パイプ -> sudo tee 経由で目的のファイルに渡すパターン。teesudo 権限を持つので ./testfile に書き込むことができます。tee から標準出力への出力は /dev/null に捨てます。

$ sudo tee ./testfile > /dev/null << EOF
> xyz
> EOF
$ sudo cat ./testfile
xyz

最後に

sudo sh -c パターンが一番わかりやすいと感じました。よりよい解決方法などがありましたらコメントで教えてもらえると嬉しいです。

参考

sudo(8) - Linux manual page

https://man7.org/linux/man-pages/man8/sudo.8.html

Redirections - Bash Reference Manual

https://www.gnu.org/software/bash/manual/html_node/Redirections.html

LICENSE

クリエイティブ・コモンズ・ライセンス

本記事は CC-BY-SA-4.0 ライセンスの下に公開しています。
このライセンス文の日本語版は下記ページをご確認ください。

https://creativecommons.org/licenses/by-sa/4.0/deed.ja

脚注
  1. 特定のファイルディスクリプタからの出力先ファイルを指定する機能。 ↩︎

  2. bash にも -c オプションがあるので。 ↩︎

Discussion