• ベストアンサー

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

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

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

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4844/10253)
回答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% (4844/10253)
回答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% (4844/10253)
回答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

  • PHPからシェルコマンドの実行

    PHPからシェルコマンドを実行したいのですが SSHやSCPコマンドが使えません。 phpからlsなどは問題なく実行できます。 具体的には以下のように書いています。 `scp test.log user@host:/home/hoge`; shell_exec()を使っても実行されませんでした。 環境は以下のとおりです。 PHP 5.4.17 CentOS 5.8 sshやscpコマンドをphpから実行するには何か特別な方法が必要なのでしょうか。 ご存知の方、教えてください。

    • ベストアンサー
    • PHP
  • Linuxシェルスクリプトを新しいコマンドにしたい

    Linux初級者です。よろしくお願いします。 OSにFedora Core 10, シェルにtcshを使用しています。 よく使用するコマンドを、まとめて一括で実行するように、 新しいコマンドを作成したくて、次のようなことをしていたのですが (1)ホームディレクトリにmybinというディレクトリを作成してPATHを通す。 (2)newbin1という以下の内容のシェルスクリプトを作成して、~/mybinに置いておく。 ================================== #!/bin/tcsh -f date #実行コマンド例1 echo $PATH #実行コマンド例2 ================================== (3)chmodコマンドでファイルに実行権限を与える。 上記のような方法で、作成したシェルスクリプト(newbin1)を PATHの通ったディレクトリ(~/mybin)に置いて、 > newbin1 とコマンドを呼び出しても、 "newbin1: コマンドが見つかりません" というエラーになってしまいます。 > which newbin1 とすると、ちゃんとファイルのパスが表示されるのですが、 *********************************************************** 自分で作成したシェルスクリプト(newbin1)を、 新しいコマンドとして認識させるにはどのようにすればよいのでしょうか。 また、そもそもシェルスクリプトを新しいコマンドにすることが 不可能だったりするんでしょうか? ************************************************************ 一括で実行したいコマンドが多い場合に、aliasで割り当てるのが大変なので、 できればaliasコマンドは使わずにできる方法を探しています。 基本的な質問かもしれませんが、よろしくお願い致します。

  • scpコマンドで、「追記」のオプションはありますか?

    scpコマンドで、「追記」のオプションはありますか? 会社で、scp(scp2)のコマンドを組み立てている、Cシェルの改修をすることになりました。 私は"scp"というものを知ったのがここ数日、Cシェルもかろうじて読めるくらいなのですが、そのシェルを作った方がもう退職されてしまったため、私が改修することになりました… 概要は、SSHサーバ上にあるファイルを別サーバへコピーしているのですが、それを「追記」できるようにしたいのです。 いくつかサイトを見てみたのですが、それらしきオプションがある、というのは見つけられませんでした。 もう、手も出せず困っています。。。 どなたか、詳しい方からのご教示をお待ちしております。

  • リスト内の各ショートカットの参照先を一括取得したい

    windowsのエクスプローラーのショートカット(拡張子.lnk)のフルパスのリストがあります。 リスト内の各ショートカットの参照先を、コマンドプロンプトやパワーシェル等で一括で取得したいです。 方法をご存知の方、教えてください。 よろしくお願いします。

  • シェルの実行中にユーザ切り替えてコマンド実行

    はじめまして。 シェル初心者です。 shell.shをrootユーザでクーロン実行していますが、 shell.shの処理の中で、違うユーザでコマンド実行したいのですが、 可能かどうかも、方法が分かりません。 教えていただけないでしょうか。 環境はLinuxです。 下記のコマンドを実行したいです。 リモートでログインしてコマンド実行結果を取得する ssh -l tomcat server_tomcat grep test /tmp/test.log ※他のユーザでsshを実行してコマンド結果を取得したいです。 以上。宜しくお願い致します。

  • コマンドをフルパスで入力する理由

    ちょっと質問なのですが、コマンドをフルパスで入力するのとそうでないのとでは違いは大きいでしょうか。たとえば、 /bin/grepとか。 スクリプトの中にたくさんコマンドを詰め込んでサーバーに負荷を 与えてチェックした所、省略したコマンドだと通常は実行できるはずが、 負荷のせいなのか、コマンドが見つからないというエラーになりました。 対してフルパスで指定してから負荷テストを行うとコマンドを 実行してくれました。 できればコマンドが多い分、スクリプトの中をすっきりさせる為に コマンドを略して記述したいのですが、フルパスで指定したほうが よいものでしょうか。。

  • sedコマンドをシェルで実行でうまくいかない

    sedコマンドをシェルで実行しようとしています。 sedコマンドの引数がシングルクォートのためうまく出来ずに困っています。 テキスト内の /abc を xxx と変えたいとします。 以下のように作ってみました。 #!/bin/sh a='\/abc' b=xxx sed \'$a/$b\' txt しかし 認識できないコマンドです: '\/abc/xxx' というエラーが出ます。 $aで扱いたい変数は実はもっと長いパスの為、 ぜひ変数を使いたいのですが、うまくやる方法は無いでしょうか。

  • 【シェル】whileコマンドについて

    【シェル】whileコマンドについて OS:Solaris10 SH:Bシェル お世話になります。 whileコマンドにてテキストから、先頭に"#"(シャープ)が付いている行と、 空白行以外を読み込ませたいです。 ところが、メイン処理にawkコマンドを入れると、テキストを読む時点で、 行全体ではなく、指定したフィールド内の文字列を読みにいくため、 "#"(シャープ)が付いている行を無視することができません。 ====== while.sh ====== #!/bin/sh while read LINE do echo $LINE | awk '{print $2}' done < list.txt | grep -v "^#" | grep -v "^$" ====================== ------ list.txt ------ 1 2 3 #4 5 6 7 8 9 ---------------------- ****** 出力結果 ****** 2 5 8 ********************** ** 出力させたい結果 ** 2 8 ********************** whileコマンドのオプション等で、テキスト内に特定の記号がある行は 無視して読み込ませる方法がありましたら、ご教授ください。 宜しくお願い致します。

  • 他ユーザーのシェルスクリプト実行

    他ユーザーのシェルスクリプトを実行する際に「rsh」や「ssh」を使用しないで実行 する方法が知りたいです。 また、シェルはCのプログラムから実行させたいのでパスワードの入力を求められたり するのは避けたいです。 フルパスを直接指定すれば実行は出来ましたが、ユーザーが変わっていないので ほしい結果が得られませんでした。 OSはredhat linuxです。

  • perlからsystemコマンド呼ばれる時のシェルについて

    HP-UX/perl4 で作成したスクリプトを、Linux(Red Hat)/perl5 へ移植するに当たって、system関数の動作が異なり困っています。 HP-UX では ksh をシェルとして使用していたため、perl からのsysytem関数で実行するsystemコマンドも、kshで動作するものを使っていました。Linuxでもログインシェルをkshに設定しました。 ところが、HP-UXで使っていたprintコマンドが使用できず、以下のエラーメッセージが出ます。 sh: print: command not found シェルはkshを指定していても、perlからsystem関数やバッククウォート`` でシステムコマンドを実行するときは、shが使われるようなのです。 perl内の記述は以下のとおりです。 system("print 'a'"); "print"の前に"ksh "をつけたり、"print"を"echo"に変えると、正しく動作します。 移植するperlの本数が多いのと、print以外にもこの問題が起きるかもしれませんので、できれば perl 内からのシステムコマンド実行時にもログインシェルとおなじ ksh で動くようにしたいのですが、どのようにすればよいのでしょうか? よろしくお願いいたします。