既存のコードライブラリを操作しようとしていますが、問題が発生しました。要するに、私はシェルスクリプト(これをA
と呼びましょう)を実行します。その最初の行為は別のスクリプト(B
)を呼び出すことです。スクリプトB
は現在のディレクトリにあります(使用しているプログラムの要件)。ソフトウェアのマニュアルはbash
を参照していますが、A
のコメントは、それがksh
で開発されたことを示唆しています。私はこれまでbash
で運営してきました。
A
内では、B
を実行する行は単純です。
_. B
_
「ドットスペース」構文を使用してプログラムを呼び出します。 Sudo
のような異常なことは何もしません。
ドットスペース構文なしでA
を呼び出すと、次のようになります。
_./A
_
ファイルB
が見つからないと常にエラーが発生します。 pwd
、ls
、whoami
、_echo $Shell
_、および_echo $PATH
_行をA
に追加してデバッグし、B
は実際にはそこにあり、スクリプトはコマンドプロンプトで実行しているのと同じ_$Shell
_で実行されており、スクリプトは私と同じユーザーであり、スクリプトの検索パスは同じです_$PATH
_私と同じように。また、次のことも確認しました。
_. B
_
コマンドラインでは、問題なく動作します。しかし、A
内の構文を次のように変更すると次のようになります。
_./B
_
代わりに、A
が正常に実行されます。
同様に、ドットスペース構文でA
を実行すると、_. B
_と_./B
_の両方が機能します。
要約:
_./A
_は、A
に_./B
_構文が含まれている場合にのみ機能します。
_. A
_は、_./B
_または_. B
_構文のいずれかでA
に対して機能します。
ドットスペース(つまり、_. A
_)構文の使用は、サブシェルにフォークせずに実行されることを理解していますが、ファイルが明らかにそこにあることを考えると、これが私が観察している動作にどのようにつながるかはわかりません。構文や親/子プロセスワークスペースのニュアンスについて私が見逃しているものはありますか?魔法?
PDATE1:ksh
を使用しているときに、スクリプトがbash
で開発された可能性があることを示す情報を追加しました。
PDATE2:_$PATH
_が同じであることを確認するためのチェックを追加しました。
PDATE:スクリプトはksh
用に作成されたと言っていますが、bash
で実行されています。 Kensterの回答に応えて、コマンドラインで_bash -posix
_を実行してから_. B
_を実行すると失敗することがわかりました。これは、コマンドラインとスクリプトの環境の違いは、後者がPOSIX準拠モードでbash
を実行しているのに対し、コマンドラインはそうではないことを示しています。もう少し詳しく見てみると、これはbash
man
ページにあります。
Shとして呼び出されると、bashはスタートアップファイルが読み取られた後にposixモードに入ります。
Shebang
のA
は確かに_#!/bin/sh
_です。
要約すると、ドットスペース構文なしでA
を実行すると、Shebang
が_#!/bin/sh
_であるため、POSIX準拠モードである独自のサブシェルにフォークします(たとえば、 、_#!/bin/bash
_。これは、コマンドライン環境とスクリプトランタイム環境の重大な違いであり、A
がB
を見つけることができなくなります。
コマンドパスがどのように機能し、いつ使用されるかから始めましょう。次のようなコマンドを実行すると、次のようになります。
ls /tmp
ここでのls
には/文字が含まれていないため、シェルはコマンドパス(PATH環境変数の値)内のディレクトリでls
という名前のファイルを検索します。見つかった場合は、そのファイルを実行します。 ls
の場合、通常は/bin
または/usr/bin
にあり、これらのディレクトリは両方とも通常はパスにあります。
コマンドWordで/を使用してコマンドを発行すると、次のようになります。
/bin/ls /tmp
シェルはコマンドパスを検索しません。特にファイル/bin/ls
を探し、それを実行します。
./A
の実行は、名前に/を含むコマンドの実行例です。シェルはコマンドパスを検索しません。特に./A
という名前のファイルを探し、それを実行します。 「。」は現在の作業ディレクトリの省略形であるため、./A
は現在の作業ディレクトリにあるはずのファイルを指します。ファイルが存在する場合は、他のコマンドと同じように実行されます。例えば:
cd /bin
./ls
/bin/ls
を実行すると機能します。
. A
の実行は、ソーシングファイルの例です。ソースとなるファイルは、シェルコマンドを含むテキストファイルである必要があります。これは、新しいプロセスを開始することなく、現在のシェルによって実行されます。ソースとなるファイルは、コマンドが見つかるのと同じ方法で見つかります。ファイルの名前に/が含まれている場合、シェルは指定された特定のファイルを読み取ります。ファイルの名前に/が含まれていない場合、シェルはコマンドパスでそのファイルを探します。
. A # Looks for A using the command path, so might source /bin/A for example
. ./A # Specifically sources ./A
そのため、スクリプトは. B
を実行しようとしますが、現在のディレクトリにB
という名前のファイルがある場合でも、B
が存在しないと主張できません。上で説明したように、B
には/文字が含まれていなかったため、シェルはコマンドパスでB
を検索していました。コマンドを検索するとき、シェルは現在のディレクトリを自動的に検索しません。現在のディレクトリがコマンドパスの一部である場合にのみ、そのディレクトリを検索します。
つまり、「。」がないため、. B
はおそらく失敗しています。 (現在のディレクトリ)コマンドパスにあり、B
をソースしようとしているスクリプトは「。」と想定しています。あなたの道の一部です。私の意見では、これはスクリプトのバグです。多くの人が「。」なしで走ります。それらのパスにあり、スクリプトはそれに依存するべきではありません。
編集:
ksh
を使用しているときに、スクリプトはbash
を使用すると言います。 KshはPOSIX標準に従います-実際、KSHはPOSIX標準の基礎でした-そして私が説明したように常にコマンドパスを検索します。Bashには「POSIXモード」と呼ばれるフラグがあり、その方法を制御します。厳密にはPOSIX標準に準拠しています。POSIXモード(一般的に使用されている方法)でない場合、bashは、コマンドパスにファイルが見つからない場合、ソースとなるファイルの現在のディレクトリをチェックします。
そのbashインスタンス内でbash -posix
を実行して. B
を実行した場合、それが機能しないことがわかるはずです。