最近WSL上のUbuntuのシェルをfishに変えたらLive Shareをインストールしてくれと出るようになりましたが、インストールに失敗します。自動で実行されるコマンドがfishの文法で無いためです。そのため、fishに対応したコマンドに書き換えてあげるとコマンドが実行されるようになります。
もともとのコマンドは次のとおりです。
clear && echo 0 > "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/terminal-exit-code-684349" && "/bin/bash" "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/deps/linux-prereqs.sh" || echo $? > "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/terminal-exit-code-684349" && exit 0
このコマンドの、
echo $?
部分がfishのコマンドでは使えません。fishはこのコマンドを実行しようとするとき、「$statusを使え」と表示されます。そのためその部分を書き換えます。
clear && echo 0 > "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/terminal-exit-code-684349" && "/bin/bash" "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/deps/linux-prereqs.sh" || echo $status > "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/terminal-exit-code-684349" && exit 0
これでコマンドが実行されます。パスワードを入力してインストールして終了。
個人的なメモ
私は全くのシェル初心者なので、そもそもこれがなにかわかっていませんでした。そのため、勉強のためにコマンドを読み解きたいと思います。
まずコマンドは前から順番に評価されます。なので、今回のように
command A && command B && command C || command D && command E
ならば、Aを評価、trueならBを評価、trueならCを評価。次に、直前の評価がtrueならばDを評価せず、falseならDを評価。最後に直前の評価がtrueならEを評価、falseならEを評価しないという流れです。パイプをイメージすればわかりやすかったです。
claer
画面をクリアするコマンドです。次のコマンドが画面の最上段へ移動します。
&&
制御演算子の一つ。fishはv3から&&に対応しています。コマンドを連続して使うことができます。前のコマンドの終了コードがtrueならば次のコマンドが実行されます。
echo 0 > file
0という文字列をfileに上書きします。fileが存在しなければ作成して文字列を上書きします。
echo [文字列] > [書き込みファイル名]
として使うようです。
"/bin/bash" "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/deps/linux-prereqs.sh"
は、linux-prereqs.shというシェルスクリプトを実行します。
試しに次のようなシェルスクリプトを作成してみました。
#!/usr/bin/bash
echo Hello-World!
実行権限を与えて実行してみます。シェルはfishです。
./hello.sh
Failed to execute process './hello.sh'. Reason:
The file './hello.sh' specified the interpreter '/usr/bin/bash', which is not an executable command.
シェルをbashに変更して実行してみます。
bash: ./hello.sh: /usr/bin/bash: bad interpreter: No such file or directory
インタープリタが違うと怒られています。シバンが"/usr/bin/bash"なのに、bashの位置は"/bin/bash"でした。なのでシバンを書き換えればbashで動きます。fish shellでもちゃんと動作します。またはシバンを書き換えずに、次のように実行してみても動きます。
bash ./hello.sh
または、今回のコマンドのように
"/bin/bash" "hello.sh"
でも実行できました。
さて、linux-prereqs.shのシバンは”/usr/bin/env bash"でした。
これは、スクリプト実行時にPATHからインタプリタを検索し実行します。bashがどこにあろうが動くわけです。なので、このスクリプトをそのまま実行しても動きます。しかし、その前に"/bin/bash"とあります。これは必要なのでしょうか?
調べてみると、この書き方にはシバンを読み込まず、別途bashを起動し、ファイルに実行権がいらないという特徴があるようです。
そのため、ファイルに実行権がなくても実行できるようにするためにこういう書き方をしていると思われます。
linux-prereqs.shを実行すると、Visual Studio Live Share Linux Dependency Installerが起動します。
ここで||演算子が入り、今までの処理のいずれかが正常終了していないならば次のコマンドが実行されます。
echo $? > "/home/jago39/.vscode-server/extensions/ms-vsliveshare.vsliveshare-1.0.3912/out/terminal-exit-code-684349"
コマンド終了時に終了ステータスが特殊変数$?に自動で設定されます。その終了コードを指定のファイルに上書きするようです。
fishの場合は$statusという変数名に変わっています。
そして最後に、
&& exit 0
を実行します。シェルを終了させるコマンドです。
||以前が全て正常終了していれば、その次のコマンドが評価されずにこのコマンドが評価されます。
また、||以前のいずれかが異常終了した場合は||の後ろのコマンドが評価され、このコマンドは(多分)必ず正常終了するため、この終了コマンドが評価されます。
明示しない場合は、最後に実行されたコマンドの終了ステータスが適用されるらしいです。