WSL で sh スクリプトを実行すると、「コマンドが見つかりません」というメッセージが返されます 質問する

WSL で sh スクリプトを実行すると、「コマンドが見つかりません」というメッセージが返されます 質問する

wsl がインストールされているので、cmd プロンプトから次のコマンドを実行します。

wsl ls

完璧に動作しますが、script.sh ファイルを作成して試すと、

wsl script.sh

内側:

ls

または他の Linux コマンドを実行すると、次のようになります:

/bin/bash: script.sh: command not found

もちろん、スクリプトは正しいフォルダにあります。問題の原因は何ですか?

編集: 回答をありがとうございます。.sh ファイルを wsl に関連付けて、ダブルクリックで自動的に実行することは可能ですか?

ベストアンサー1

表面的には、これは非常に単純な質問です。 コマンドを使用してコマンドを実行することに関する多くの質問に回答してきましたwsl。ただし、この質問は微妙に複雑です。次の方法で、問題に 2 つの側面を追加しました。

  • パスなしでスクリプトを実行しようとしています。
  • 使用していないシェバンライン

どちらも必須しかし、舞台裏で何が起こっているのかよくわかっていないと、問題が発生します。

まず、あなたの質問に対する「短い答え」を述べ、その後、他の技術の説明と欠点について詳しく説明します。

簡単なスクリプトがありscript.shますただ次の:

ls

スクリプトは現在のディレクトリにあります。wslコマンド (PowerShell、CMD、またはその他の Windows プロセスから) で実行するには、次を使用します。

wsl -e sh script.sh

しかし、そうしないでください。シェバン行を使用する習慣をつけてください。スクリプトを次のように編集します。

#!/usr/bin/env sh
ls

デフォルト ユーザー (既に設定されているようです) に対して実行可能に設定します。次に、次のコマンドで起動します。

wsl -e ./script.sh

私の知る限り、これら2つのテクニックだけがスクリプトを効率的に実行できます。wslコマンドからスクリプトを起動する他の方法は、複数シェルの読み込み - シェルの中にシェルがあるか、シェルがシェルexecをロードしています。

なぜですか-e?何をするのですか?

wsl -e(または長い形式のwsl --exec) の場合、ヘルプには次のように記載されています。

デフォルトのLinuxシェルを使用せずに指定されたコマンドを実行します

これにより、デフォルトのシェルを実行するオーバーヘッドを発生させることなく、シェルを完全にスキップしたり、別のシェルを指定したりできるようになります。

したがって、 を実行するとwsl -e sh script.sh、次のようになります。

  • WSLにすぐに実行するように指示するsh
  • sh各行を読んで解釈するように指示しますscript.sh(「読んで解釈する」の理解を深めるには以下を参照してください)。

wsl -e ./script.shシェバン行を含むスクリプトを実行すると、次のようになります。

  • WSLにすぐに実行するように指示する./script.sh
  • WSL の/initプロセス (実際にはこれらすべてのケースで実行されますが、明示的に言及する必要があるのはこのときだけです) は、スクリプトの最初の行がシバンであることを認識し、そのシェルでスクリプトを直接読み込んで実行します。
他の起動方法が機能しないのはなぜですか?

他のテクニックを使用すべきでない理由を説明すると、本当に複雑になってきます。次のことを理解する必要があります。

  • シェルに次のことを要求すると何が起こるか実行するパスを指定していないスクリプト ファイルですか?
  • 一方、シェルに解釈するbashパスを指定していないスクリプト ファイルですか? シェルによって異なる場合があることに注意してください。ここでは、使用しているシェルに従います。
  • あなたの場合、WSL は何をしようとしているのでしょうか?
  • シェルにシェバン行を含むスクリプトを実行するように指示すると何が起こるでしょうか?
  • 一方、あなたがやっているように、シェルにスクリプトを実行するように要求するとどうなるでしょうかそれなしシバンライン?
  • -eコマンドの引数--wsl引数がある場合とない場合では何が起こるでしょうか? もちろん、これについてはすでに上で説明しました。

わあ!そう?!全部?

それを念頭に置いて、スクリプトを実行する他の方法の例と、それが機能しない理由、または効率が悪い理由をいくつか挙げてみましょう。


wsl script.sh(あなたのオリジナルの例)

これは Linux/WSL 内から実行するのと同じだと思うかもしれませんbash script.shが、実際はそうではありません。

bash script.sh(WSL内では)動作します。読みと解釈スクリプトの各行をbash単独で実行されるコマンドとして記述します。実行中スクリプトでは、パスは必要ありません。シェルは現在のディレクトリ内のファイルを読み取るだけです。

wsl script.sh(WSL外では)動作しません。なぜなら、実際には実行するスクリプトは、デフォルトのユーザーのシェル (bashこの場合は ) を使用して実行されます。これは、bash -c script.shWSL/Linux 内から呼び出すのとほぼ同等です。ファイルを実行するには、ファイルが検索パス (環境変数によって表される) 内のディレクトリにあるか、ファイルへの絶対パスまたは相対パス (例:または)PATHを指定する必要があります。bash -c ./script.shwsl ./script.sh

スクリプトの実行と解釈の違いについての詳細は、次のサイトをご覧ください(ただし、この用語は正確には使用されていません)。この優れたUnix & Linuxスタックの回答


wsl sh script.sh(またはwsl sh ./script.sh

どちらか意思スクリプトを実行しますが、実際にはシェルが 2 回ロードされます。これは次のようになります。

  • デフォルトのシェルを起動します ( bash)
  • 実行を依頼するbash-csh script.sh
  • bash振り返ってexecshプロセスをプロセスbashに置き換えて)sh
  • それからsh 読んで解釈する(それよりも実行する) スクリプトを実行します。

はスクリプトを読み取って解釈するためsh、パスを必要とせずに (またはファイルが 上のディレクトリにある必要もなく$PATH)、現在のディレクトリからその処理を実行できます。

しかし、2 つの異なるシェルをロードするのは意味がありません。 オリジナルはwsl -e sh script.shのみを実行しshbash完全にスキップして、ロード時間を節約します。

注: この場合、シェバン行があるかどうかは関係ありません。シェバンは、実行中スクリプトでは、shその行をコメントとして認識します。読みと解釈そしてそれをスキップします。


wsl ./script.sh(シェバン行なし)

2 つのシェルもロードします。これは を実行するのと同じであることを覚えておいてくださいbash -c ./script.sh

  • ロードbash(または異なる場合はデフォルトのシェル)
  • シェル(Bash)に./script.sh現在のディレクトリから実行するように指示します
  • Bash は、ファイル内に shebang がないことを確認し、Bash の「フォールバック」シェル (つまり、自分自身) で実行することを決定します。
  • そのため、Bash は現在のプロセスを置き換えて、スクリプトを実行するexec新しいプロセスを作成します。bash

wsl ./script.sh(シェバンライン付き)

これは「no shebang」の場合と非常に似ていますが、「fallback」に戻る代わりに、Bash は shebang 行 (shこの場合は) で指示されたものを使用します。

これは依然としてexecのインスタンスでありsh、親を置き換えてbashプロセスを呼び出します。


wsl -e sh -c ./script.sh

それは機能するはずですよね? つまり、WSL にshスクリプトを読み込んで実行するように指示しているのです。他に何ができるでしょうか?

はい、またしても動作します。しかし、ここでもシェルを2回ロードしています。1回は明示的に( 経由で-e)そしてもう1回はシェルがどうやってスクリプトを実行します (shebang またはフォールバック経由)。

これを確認するには、スクリプトを次のように変更するのが最も簡単です。

ps -ef

シバンがない場合、wsl -e sh -c ./script.sh次を返します:

  PID TTY          TIME CMD
 2638 pts/1    00:00:00 sh
 2639 pts/1    00:00:00   sh
 2640 pts/1    00:00:00     ps

シェバンを使用すると、wsl -e sh -c ./script.sh次が返されます:

  PID TTY          TIME CMD
 2643 pts/1    00:00:00 sh
 2644 pts/1    00:00:00   test.sh
 2645 pts/1    00:00:00     ps

提案された ではwsl -e ./script.sh、次のことがわかります。

  PID TTY          TIME CMD
 2651 pts/1    00:00:00 test.sh
 2652 pts/1    00:00:00   ps

でも待って、まだあるの?

もしこれがシェル/スクリプト/シェバンの悪夢を引き起こすのに十分でないなら、時々あなたが意思たとえその後に方向転換してサブプロセスをロードすることになったとしても、親シェルを実行したいのです。

スクリプトがスタートアップファイルから何かを必要とする場合に、これが当てはまります。どれでも前のコマンド ラインでは、WSL はシェルを非ログイン、非対話型シェルとして起動します。

~/.bashrcこれは、と が処理されないことを意味し、スクリプトが期待する と に変更を加えた場合 ( またはその他の環境変数など) に~/.bash_profile混乱が生じる可能性があります。PATH

その場合は、次のように呼び出します。

wsl -e bash -lic ./script.sh

これにより、「ログイン、対話型」シェルが強制され、起動構成が処理されます。

これを強制するためにシェバン行を変更することも可能かもしれませんが、この回答/本/論文はかなり長くなったため、その説明は省略します ;-)

さらに詳しく知りたい方は、この質問必要であれば。

おすすめ記事