• ベストアンサー

コマンドラインとシェルで参照先が変化する理由

sshとかscpとかでコマンドだとパスワードなしでアクセスできるのに シェルにするとパスワードを聞かれるようになるという現象がよくあります。 で、which で調べると異なるsshを使っているとか、よくあるオチだと思います。 このときに今までは仕方がなくシェルの記述をフルパスで指定するなどしていました。 しかしふと振り返ると、なぜそのようなことが生じるのかよくわかりません。 PATHに記述してあるとおりに読み込んでいく気がするし。 また、理由がわかるとシェルで使うパスの順も制御でき、 フルパスで指定しなくて良くなるのではないかと思いました。 で、質問です。 ・参照先が変わるのでしょうか ・この優先順位は制御できるものなのか(できるのならその方法も) ・フルパスで指定する以外の対処方法 以上よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.7

#3,#6です。 回答がほとんどかぶりましたね。 確かに、スクリプト中ではまずaliasは使いませんね。関数は使いますが。 スクリプト中で、/bin /usr/bin 以外の場所にあるコマンドを使うときによく使われるのは、よく見かける順で書くと、 (1) newcmd=/some/other/bin/newcmd してから $newcmd と書く (2) PATH=$PATH:/some/other/bin してから使う(前に付けることも) (3) フルパスで書く

mibusys
質問者

お礼

ふむふむ。なるほど。 今後同様の問題にどのように対応していくことが望ましいのか どのような記述が一般的なのかがだいぶわかってきました。 ありがとうございました。

その他の回答 (6)

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.6

#3です。 >しかし、一番やりたいことはシェルから実行したときの参照先をコマンドラインと同じにすることです。 ああ、逆でしたか。以下bash限定の話ですが、 alias展開は、シェルオプションのexpand_aliasesがセットされているときだけ有効で、これは対話シェルの場合デフォルトでオンで、非対話シェルの場合はデフォルトオフです。スクリプトの中で有効にするには shopt -s expand_aliases >${GZIP_BINDIR-'/bin'} >・なぜハイフンがあるのか これは、「シェル変数または環境変数の GZIP_BINDIR がセットされていればその値に、もしセットされていなければ /bin に」展開されます。 似たものに ${GZIP_BINDIR:-'/bin'} があり、これは、「シェル変数または環境変数の GZIP_BINDIR がセットされており値が空文字列でなければその値に、もしセットされていないか、仮にセットされていても値が空文字列ならば /bin に」展開されます。 BBB=${AAA:-xxx} をわかりやすく書き換えると、 if [ "$AAA" != "" ] then BBB=$AAA else BBB=xxx fi >・なぜ「/bin」がクォーテーションでくくられているのか この場合、特に意味はないですね。囲まなくても同じです。 以上、すべて、man bash に書いてあります。シェルプログラミングを本気でするなら、まずman bashを通読しましょう。これは「Cプログラミングをするなら、まずCの文法を全部理解しましょう」と同じ。C関数は全部覚えなくても必要に応じてリファレンスを見ればいいので、それと同じ意味でman bashを全部記憶する必要はないですが、通読は必要です。

mibusys
質問者

お礼

> シェルプログラミングを本気でするなら、まずman bashを通読しましょう。 うぅ。耳が痛いです。 大変参考になりました。ありがとうございました。

回答No.5

> しかし、一番やりたいことはシェルから実行したときの参照先を > コマンドラインと同じにすることです。 > シェルの中でaliasの記述をしてみましたが効きませんでした。 > これをシェルの実行をaliasの効いているコマンドラインと > 同じものにする方法がありますでしょうか?もしあるのであれば > 教えてください。 シェルスクリプトの挙動はシェルの種類によって異なりますが、bashをお使いだと考えて正しいでしょうか。 bashの場合は、 * 通常はシェルスクリプト内でaliasは無効になる * シェルスクリプトが実行される際には .bashrc は読み込まれない という点に注意が必要そうです。 前者の振る舞いを変更するには、当該シェルスクリプトの始めの方に「shopt -s expand_aliases」と書けばいいはずです。 後者の振る舞いを変更するには、シェル変数 BASH_ENV に「~/.bashrc」を設定すればいいようです。これはシェルスクリプト内に書くのではうまくいかないので、当該シェルスクリプトの起動を「BASH_ENV='~/.bashrc' XXX.sh」のように行うなどで対応することになります。あるいは、BASH_ENVは使わずシェルスクリプト内で「source ~/.bashrc」などを実行してしまう方がいいケースもあるでしょう。 expand_aliasesやBASH_ENVの説明は「man bash」を実行して表示されるマニュアル内に書かれています。 ただ、aliasに依存したシェルスクリプトはあまりよくないように思います。シェルスクリプト内ではフルパスを指定するのが基本ではないでしょうか。

参考URL:
http://www.linux.or.jp/JM/html/GNU_bash/man1/bash.1.html#lbBO
mibusys
質問者

お礼

>bashの場合は、通常はシェルスクリプト内でaliasは無効になる そうなんですか。勉強になります。 >当該シェルスクリプトの始めの方に「shopt -s expand_aliases」と書けばいいはずです。 おぉ。方法はあるんですね。 >シェルスクリプト内ではフルパスを指定するのが基本ではないでしょうか。 なるほど。私は基本がなってないので試行錯誤している感じなのですが ご経験がある肩のご意見は参考になります。 ありがとうございました。

  • OKwebb
  • ベストアンサー率44% (92/208)
回答No.4

#1です。 > 同じユーザーの場合でも同じことが言えるのでしょうか? 同じユーザーでもありえると思います。 例えば#1で記載しているクーロンの例で言えば、crontabにてPATHを記載すればそのPATHで、記載しなければデフォルトのPATHで動作したと思います。 それは、ログインシェルで使用している~/.bash_profile等で有効になっているPATHとは違うかもしれません。

mibusys
質問者

お礼

これは結局、実行前にPATHの内容が 変更されているケースということですね。 今回の私のところで起きていた問題とは異なっていましたが ご回答ありがとうございました。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.3

PATHが同じで、違うコマンドが実行されるとしたら、シェルのaliasですね。 aliasコマンドで、現在の設定を確認してみてください。 unaliasコマンドでとりあえず解除できます。もしくはコマンド名に\を前置するか。 根本的にはシェルの設定ファイルから削除するか、システム設定ファイルで定義されているなら、個人用設定ファイルでunaliasを追加ですね。 あと、bashだとaliasじゃなくて関数の可能性もあります。setコマンドで表示。

mibusys
質問者

お礼

ありがとうございました。

mibusys
質問者

補足

確認してみました。確かにaliasの設定がありました。 .bash_profile(実際には.bash_profileから.bashrcが呼ばれている?)の設定で aliasが設定されていました。 で、コマンドラインから「which ssh」としたときと 同一ユーザーで「which ssh」と記述したシェルを実行したときで 結果が異なりました。 unaliasを行なうことで、コマンドラインの参照先を シェルと同じものにすることはできました。 しかし、一番やりたいことはシェルから実行したときの参照先をコマンドラインと同じにすることです。 シェルの中でaliasの記述をしてみましたが効きませんでした。 これをシェルの実行をaliasの効いているコマンドラインと 同じものにする方法がありますでしょうか?もしあるのであれば教えてください。 ここまでの情報でも参考になりましたが もう少し教えてください。よろしくお願いします。

回答No.2

コマンドを呼び出す時にはPATH環境変数に指定されたディレクトリを先頭から順番に探していきますが、このPATH環境変数は実行したユーザーのPATH環境変数 (echo $PATHで表示されるもの) が使われます。 環境変数は親プロセスから引き継ぐため、Aさんが作成・テストしたスクリプトをBさんが実行するとうまく動かないという事はよくある事です。 以下、sh,bashスクリプトを前提にしています。 誰が実行するかわからないスクリプトであれば、PATH環境変数、LANG環境変数、umask値ぐらいはスクリプトの先頭で設定するのがお勧めです。 例えば手元の/bin/zcatコマンドはgzipコマンドを/binから探すために、次のように書かれています。 #!/bin/bash PATH=${GZIP_BINDIR-'/bin'}:$PATH exec gzip -cd "$@" フルパスで/bin/gzipとしたり、先頭にPAHT=/bin:$PATHを書くだけでも十分ですが、このようにすると後からGZIP_BINDIR=/usr/binなどとすると、/usr/bin/gzipを実行するといった柔軟性が生まれます。 スクリプトは中身が読めますから、お使いのシステムに付属するものを探してみるのも良いかもしれません。

mibusys
質問者

お礼

ありがとうございました。

mibusys
質問者

補足

最初に特に記述していませんでしたが 実行するユーザーは同一ユーザーです。 で、以下の部分なのですが参考になりそうだと思ったのですが 意味が良くわかりませんでした。 ${GZIP_BINDIR-'/bin'} ・なぜハイフンがあるのか ・なぜ「/bin」がクォーテーションでくくられているのか この辺についてもう少し教えていただけると幸いです。 よろしくお願いします。

  • OKwebb
  • ベストアンサー率44% (92/208)
回答No.1

多分コマンド実行するときとシェルを実行するときのPATH(環境変数)が違うんです。 例えばコマンド実行するユーザは一般アカウント使っていてとクーロン実行するのはrootユーザだとか、その反対だとか。 クーロン実行時のPATHがコマンド実行時と違うとか。 だからそれを同じにすれば問題はなくなります。 個人的な意見としてはフルパスで指定しとけば、そんなこと意識しなくてすむので、フルパスで指定しちゃうけど。

mibusys
質問者

お礼

ありがとうございました。

mibusys
質問者

補足

条件として書いていませんが実行するユーザーは同じユーザーです。 同じユーザーの場合でも同じことが言えるのでしょうか?

関連するQ&A