tuneoの日記: シェル力を高める:シェルスクリプト内部で環境変更 13
日記 by
tuneo
スクリプトの中で環境切り替えツールを呼び出して環境変数を変更してるんだけど、その「環境変数を変更」が/etc/profile.d/hogehoge.shの書き換えで実現されている(というか、hogehoge.shは/other/dirに置いてあるスクリプトA.sh, B.sh...などへのシンボリックリンクなので、それを張り替えてる)場合、スクリプト内に変更を反映する処理をきれいにできないものかなーと。
#!/bin/bash
#このへんは旧環境(hogehoge.sh→/other/dir/A.sh)で実行
chgenv --set B # ここでシンボリックリンクが張りなおされる
#これ以降は新環境(hogehoge.sh→/other/dir/B.sh)で実行
source /etc/profile.d/hogehoge.sh
なんちゃらなんちゃら
chgenvを解析した結果、上述のような挙動であることが分かったので、とりあえずはsource hogehoge.shして一応期待通りの動作にはなっているんだけど、もっとこう、あたかも「一度ログアウトして再度ログインしたかのように環境変更を反映させたい」という場合はどうすれば綺麗に書けるだろうか?
bash --login~とか書くと新しいプロセスになっちゃうしなー。……スクリプトの内部でexec bash --loginしたらどうなるんだっけ?
ドットコマンドでできそう (スコア:1)
ドットコマンドと直接スクリプトを実行した時の違い [hatena.ne.jp]
ただ、exportでPATHなどにいろいろと追加していると、一度logoutして再度loginした方がすっきりすることも多いですね。
Re:ドットコマンドでできそう (スコア:1)
ドットは、sourceコマンドの省略記法。既に source コマンドは使われてますね。
/etc/profile などの「sh がログイン時に自動で読み込むスクリプト」が書き換えられた時に、「ファイルを明示的に指定して source で読み込む」のが美しくない、という話かな、と理解したのですが…
> スクリプトの内部でexec bash --loginしたら
そこでスクリプトの実行は止まってしまいます。
こういうコードだと、step1 step2 は表示されますが、step3 は表示されません。
(環境変数に情報を保持しているとか、ループや条件判断の都合で)どうしても一つのスクリプトで書きたいのであれば、今のやりかたしかないと思いますが
そういった依存関係がないのなら、たぶん、一番シンプルなのは、それぞれの環境で動かすスクリプトでファイルを分けることじゃないですかね。
next.sh:
といった感じで。
Re:ドットコマンドでできそう (スコア:1)
なるほど。
ドットとsourceが同じこと、ということ知らずにドットコマンド使っていました。
よくよく調べてみると、bashでもない純粋のshではドットコマンドしか無いようですが、そういうシステムは今は少ないでしょう。
それはさておき、tuneo様のもともとやりたかったことは、
再ログインしないで環境変数をログイン直後の状態に戻す、
ということでしょうか? 私もそうしたいことはよくありますが、再ログインしてました。
こういうのはどうでしょうか?
ログイン直後に
printenv > ~/envafterlogin.sh
のようなことして、環境を保存。
戻したいときは、
source ~/envafterlogin.sh
とかする。
これだと、login直後にはなく、あとから追加された環境変数は削除されません。
envafterlogin.shに無い変数をunsetする処理をしてから戻せばokかもしれません。
ただし、実際に試していないので、問題が生じるかもしれません。
Re:ドットコマンドでできそう (スコア:1)
あたかも「ログアウトしてログインしなおした」ようにする、だけなら
# exec bash --login
すればいいのです。解説はmanページなどをどうぞ。
今回のお題は、それが「自動化すべき作業の一部」だった場合にどうするよ、というものでして。
Re:ドットコマンドでできそう (スコア:1)
なるほど。
でも、
export AAA=123
exec bash --login
しても
echo $AAA
123
とAAAは残っています。つまり「ログアウトしてログインしなおした」ようにはなっていないですね。それは私にとっては注意点です。
というか exec bash --loginを実行するシェル内では、AAAはなくなっているようで、つまりログイン直後の環境になっているみたいですが。
必要になったときは#3276326や#3276261を参考にさせていただきます。
ありがとうございました。
Re:ドットコマンドでできそう (スコア:1)
ガチで「ログアウトして再ログイン」を模倣するなら、親シェルの環境を引き継がないですからね。
そこまで必要なときはexec /bin/loginかな?ユーザ名・パスワードの入力を要求されますが。
Re:ドットコマンドでできそう (スコア:1)
よく考えたら、loginした後
すぐ、
bash として新しいshellに入り、
env1 設定
job1 実行
exit
これで元の環境に戻るから、自動的にlogin直後の環境に戻る、
bash
env2 設定
job2 実行
exit
として行けば良いような気がしてきました。
ただ、いろいろやっている間に自分がどの環境にいるのかわからなくなってくるから、promptにでもそれがわかるような印をしておけば、よいのかも。
自動実行の場合も、基本は上のをそのままスクリプトにすれば bash --login -cは使わなくても何とかできそう。
bash --login関連で新しいまっさらなシェルが開ければもっと良いのですが。
Re:ドットコマンドでできそう (スコア:1)
>いろいろやっている間に自分がどの環境にいるのかわからなくなってくるから、
脇目も振らずに同じttyを注視し続けているという決め付けは必ずしも…
ということも考えられる。そこで
>promptを変更して
以外の選択肢
・踏み切りが遮断する・パトランプが鳴動する
・syslogに[notice]を飛ばす
・猫(ぬいぐるみ可)をアイスホッケーのペナルティボックスに軟禁
…など、状態を明らかにするべく適宜目印を設定/解除する提案を。
Re:ドットコマンドでできそう (スコア:1)
そういうのは面白いですね。
ただ、実装は難しそうというか、大変そう。
でもやったらオオウケかも。
なにしろ実際のシェルやスクリプトが動いているのは遠く離れたリモートホストかもしれないですから。
Re:ドットコマンドでできそう (スコア:1)
>「自動化すべき作業の一部」
はログイン中のユーザが動作させる前提なのですか?
そうではなくcrontabにぶち込んでやらせる形式とか
JP1なんたら(日立のプロプラ、他社にもいろいろあるはず)にやらせる?
su - $USER "-c $command"
でも現環境変数引き継ぐんだっけ(solaris の man(1M)ではそう書いてた)
すっきりと別ユーザのアカウント作るような改修は不許可なんだろな。
Re:ドットコマンドでできそう (スコア:1)
ログイン中のユーザが動作させるのが前提ですし、別アカウントは作らない方がいいですし、別途ソフトを入れたりもしませんし、そのためのお金も出ません。
スクリプトぶち込んでしばらく他の事してれば済むので大掛かりなことはする気はないですねというか、日記を書いた時点ですでに最低限の目的は達成した後なんですよ。
こうやって書いたら動いたけど、もうちょっといい書き方はないものか、と模索をしているだけです。
Re:ドットコマンドでできそう (スコア:1)
>> スクリプトの内部でexec bash --loginしたら
>そこでスクリプトの実行は止まってしまいます。
ですよねー(苦笑)。書いてからハタと気づいて赤面しました。
解決策 (スコア:1)
詳しくはガチ業務の内容になってしまうのでぼやかしてますが、環境定義をやってる/other/dir/*.shは普通に6個とかありまして(場合によってはさらに増える)、私のミッションは各環境で所定の処理を実施し(「なんちゃらなんちゃら」のくだりですね)、結果が正常であることを確認する、というテストなんですね。
しかも各々の環境下で行う処理はそこそこ手数が多くて時間もかかるため、環境変える→ログアウト→ログイン→面倒で時間のかかる処理→終わるまでぼけーっと待つ→結果確認→最初に戻る、を手作業でくりかえすのがあまりにかったるいという事情がありまして、スクリプト書いて走らせたら離席して一服入れに行くためにやっとるわけです。
chgenv --listで環境一覧を出せるので、forループの内部でそれぞれの環境に切り替えて処理をする、というようなことをやるために頭を使ったのですが、
は完全に要らぬ心配でした。サブプロセス全然オッケー。なので解決策はこんなん。
で解決です。