本番サーバーでコマンド実行する際、権限を持っている人にコマンド実行を依頼することってあるじゃん。全台サーバーに実行みたいな。
そんな時に「このコマンドエラー出るよ」と言われないために気をつけるべきことを書いていくぞ。
1. rm, cpには\をつけてaliasを無効化しろ
サーバーによってはrmやcpに-i
をつけたものをaliasとして登録していることがある。
alias rm='rm -i' alias cp='cp -i'
-i
をつけていると以下のように削除する際、毎回確認を求めてくるようになる。
$ rm -i hoge.txt remove hoge.txt?
例えば「.txtを全て削除したい」といった際、実行者はいちいちy
を入力しないと削除できない。
$ rm *.txt remove foo.txt? y remove fuga.txt? y remove hoge.txt? ...
なので\
をつけてaliasを無効化しよう。
$ \rm *.txt
rmやcpに限った話ではないのでとりあえず付けておくことが望ましい。
2. sudoが必要なコマンドはsudoをつけろ
「rm -rf」って書いてあるんだから実行者がつけてくれるだろうと思ってはいけない。
もしくは「実行前にrootユーザーになってくれるっしょ」など他人任せにしてはいけない。
実行者としてはコピってそのまま動くのが望ましい。要するに優しさを見せましょうってことや。
# 優しさが足りないコマンド $ \rm -rf target_dir # 優しさにあふれるコマンド $ sudo \rm -rf target_dir
3. cpをする時は権限に気をつけろ
画像の保存先を変更するに、既存のディレクトリを新しい保存先にコピーすることがあるだろう。その際普通にcp
でやるなら注意が必要だ。
# public/imagesからupload/imagesにコピー $ sudo \cp -r /home/www/public/images /home/www/public/upload/images
この場合upload/imagesの所有者がrootになる。
# コピーする前は所有者がapache $ ls -l /home/www/public/ total 4.0K drwxr-xr-x 2 apache apache 4.0K 2月 23 03:50 images # コピーした後は所有者がrootに変わる $ ls -l /home/www/public/upload total 4.0K drwxr-xr-x 2 root root 4.0K 2月 23 03:54 images
そうすると画面(ブラウザ)から画像をアップロードできないなど問題が発生する。
これを防ぐためにcp
のオプションである-p
を付けよう。
# public/imagesからupload/imagesに所有者・権限もそのままでコピー $ sudo \cp -pr /home/www/public/images /home/www/public/upload/images # コピーした後も以前と属性が変わらない $ ls -l /home/www/public/upload total 4.0K drwxr-xr-x 2 apache apache 4.0K 2月 23 03:54 images
ちなみにmv
なら所有者も権限も変更されない。
4. 実行場所に依存しないようにしろ
例えば以下のコマンド。 app/shell
内のシェルスクリプトに実行権限を与える。
# app/shell配下にはshellスクリプトが置いてあるとする $ ls app/shell hoge.sh # 実行権限を付与 $ ls app/shell/ | xargs chmod +x
一見成功しそうではあるがこれは失敗する。
例えばこのコマンドを/etc
配下で実行した場合、app/shell
なんてディレクトリないよと怒られる。コマンドの実行者に「〇〇ディレクトリ配下で実行してください」などとお願いするのはナンセンスだろう。
[root@linux: /etc]$ pwd /etc # 実行場所によってエラーが出る [root@linux: /etc]$ ls app/shell ls: app/shell: No such file or directory
なのでls
で展開させるディレクトリの場所を絶対パスで書くべきである。以下のような形。
$ ls /home/www/app/shell/ | xargs chmod +x
しかしこれでも不完全だ。
なぜならlsで出力されるのはファイル名のみで絶対パス表記じゃないからである。
このコマンドを/etc
で実行するとパイプ先のxargs chmod
でhoge.sh no such file
と怒られてしまう。/etc
配下にhoge.shはないからね。
# lsで出力されるのはファイル名のみ [root@linux: /etc]$ ls /home/app/shell hoge.sh [root@linux: /etc]$ ls /home/app/shell | xargs chmod +x chmod: hoge.sh: No such file or directory
解決法としては事前にコマンドでディレクトリを移動してから実行する。
cd /home/www/; ls app/shell/ | xargs chmod +x
しかし一々移動するのもアレなのでfind
で指定してしまおう。
# findの場合、絶対パスで出力してくれる $ find /home/www/app/shell -type f -name "*.sh" /home/www/app/shell/hoge.sh # コマンド実行時にどこのディレクトリにいても実行可能 $ find /home/www/app/shell -name "*.sh" | xargs chmod +x
5. できるだけ細かくファイルは指定しろ
複数のファイルに変更を加える場合、できるだけ細かくファイルの種類を特定するべきである。
誤って他のファイルを消さないか?など、コマンドの実行者に余計な考慮をさせるわけにはいかない。
例えば以下のようなディレクトリ構造があるとする。
$ tree /home/www/public/images . |-- user1 | `-- hoge.png `-- user2 |-- foo.png |-- fuga.jpeg `-- log
「userX内の画像ファイルを消したい」コマンドを実行するとしよう。
この時images/userXには画像しかないと思い込んでいると以下のようなコマンドを実行してしまう。
$ sudo \rm /home/www/public/images/user*/*
そうするとrm: user2/log: is a directory
とエラーが出てしまう。
コマンドを実行する前にディレクトリ内は確認するとは思うが、複数サーバーが存在する場合見逃してしまう可能性もある。
このようなミスをなくすためできるだけコマンドの方で対象のファイルのみを指定するのがいいだろう。
# userX内のpngファイルのみ削除 $ sudo \rm $(find /home/www/app/images/user*/ -name "*.png")
また、以下のようにxargsで削除してもよいが、
$ find /home/www/app/images/user*/ -name "*.png" | xargs sudo \rm
もしファイル名に空白を含むものがあった場合xargs -i sudo \rm {}
などとオプションを指定する必要があるので、rm $(find ~~~)
のように$()
や``
で「コマンドの実行結果に対してコマンドを実行する」形式のほうがオプションの付け忘れ等気にしなくてすむ。
※バッククォート
だと実行者がシングルクォート
と見間違えたり見づらかったりするので$()
をおすすめする
まとめ
普段自分一人で開発している時は気にする必要はないが、コマンドの実行を依頼したりWikiに載せるときは色々気をつけたほうがいいよねって話。 要は優しさですよね。