find で見つけたファイルを sudo で実行する
実際の想定シナリオ
yocto で raspberry-pi 用に toolchain をビルドしたときに ./tmp/deploy/sdk
のディレクトリに以下のようなファイル名で、(バイナリ形式の) shell script が生成される。
poky-glibc-x86_64-core-image-full-cmdline-cortexa7t2hf-neon-vfpv4-raspberrypi4-toolchain-2.7.2.sh
このスクリプトを実行すると /opt/poky/2.7.2
以下に必要なツールチェーンがインストールされる。
課題
-
poky-glibc-x86_64-core-image-full-cmdline-cortexa7t2hf-neon-vfpv4-raspberrypi4-toolchain-2.7.2.sh
は実行したときに確認を求められる -
poky-glibc-x86_64-core-image-full-cmdline-cortexa7t2hf-neon-vfpv4-raspberrypi4-toolchain-2.7.2.sh
というファイル名は条件によって変わるかもしれないので、パスを決め打ちして実行したくない。find
で見つけて実行したい。 -
poky-glibc-x86_64-core-image-full-cmdline-cortexa7t2hf-neon-vfpv4-raspberrypi4-toolchain-2.7.2.sh
は/opt/poky/2.7.2
を書き換えるので root 権限が必要だから、sudo
経由で実行する必要がある。通常sudo
を実行する際は、対話形式でパスワードを要求される。
解決方法 (答え)
PASSWORD=xxxxx
find ./tmp/deploy/sdk -name *.sh | xargs -n 1 -I "{}" sh -c "echo ${PASSWORD} | sudo -S {} -y"
解説
poky-glibc-x86_64-core-image-full-cmdline-cortexa7t2hf-neon-vfpv4-raspberrypi4-toolchain-2.7.2.sh
のオプション
-y
オプションを指定することで y
を押したと判断してユーザーに確認を求めない。
sh ./tmp/deploy/sdk/poky-glibc-x86_64-core-image-full-cmdline-cortexa7t2hf-neon-vfpv4-raspberrypi4-toolchain-2.7.2.sh -y
これは確認を求めるプログラムでよくある話です。
find
コマンド
find の引数にフォルダ名を指定して -name *.sh
のパターンを指定することで 指定したフォルダ以下にある sh ファイルを標準出力に出力する
find ./tmp/deploy/sdk -name *.sh
xargs
コマンド
find
の出力をパイプでつないで、xargs
コマンドに渡すことで find
の結果に基づいてコマンドを実行することができる。
xargs
コマンドは通常パイプで渡されたデータを一気に起動するコマンドに渡す。
ところが今回実行したいのは shell script なので -n 1
を指定することで find
の出力一行に対してコマンドをひとつずつ実行する。
sudo
コマンドの-S
オプション (標準入力からパスワードを読み込む指定)
sudo 経由で実行する必要がある。
sudo
には -S
というパスワードを標準入力から取得するためのオプションがある。
これを使って 実行ユーザーのパスワードを標準入力から与えて sudo に渡す。
echo ${PASSWORD} | sudo -S ./hogehoge.sh param1
xargs
コマンドの-I
オプション (プレースホルダの指定)
xargs
のコマンドでパイプを含むコマンドを実行する必要がある。
xargs
には -I
というプレースホルダを指定するオプションがある。
例えば以下のようにすれば -I
に渡した {}
が動的にパイプで渡された文字列に置き換えられて実行される。
find ./tmp/deploy/sdk -name *.sh | xargs -I {} cp {} {}.bak
xargs
コマンドでパイプを含むコマンドを実行
Usage: xargs [OPTION]... COMMAND [INITIAL-ARGS]...
xargs
コマンドはオプション指定が終わった後の最初の単語を実行すべきコマンドと認識する。
このためパイプを含む文字列をダブルクォート等で囲んで COMMAND
の部分に指定できないので
COMMAND
の部分には sh
を指定する。
sh -c
を指定することでパラメータで指定したコマンドを実行できる。
これまでの内容をまとめると、最終的なコマンドは以下のようになる。
find ./tmp/deploy/sdk -name *.sh | xargs -n 1 -I "{}" sh -c "echo ${PASSWORD} | sudo -S {} -y"