はじめに
皆さんはこのコマンドを見たことがありますか?
start chrome "https://qiita.com/"
もし初めて見たという方はコマンドプロンプト(PowerShellはNG)で実行してみてください。Chromeが起動してQiitaのページが表示されるはずです。
※Chromeをインストールしてない場合は代わりに msedge
や firefox
を指定してみてください
さて、このコマンドを見て不思議に思いませんか?
なぜ C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
のようにフルパスを指定していないのにブラウザが起動するのか?
この記事ではその理由について解説してみます。
startコマンド
startコマンドとは
Microsoftのドキュメントによると、startコマンドは指定したプログラムまたはコマンドを実行するコマンドで、Windowsのコマンドプロンプトの組み込みコマンドのようです。
例えば
start notepad
を実行するとメモ帳を起動できますし、
例えば
start "現在日付" echo %date% %time%
を実行するとウィンドウ名が "現在日付" の新しいターミナルを開いて現在日付を表示させられます。
ちなみに、組み込みコマンドだからなのか、PowerShellからは直接実行できないです。
※PowerShellの start
は Start-Process
コマンドレットのエイリアス
Get-Command start
# CommandType Name Version Source
# ----------- ---- ------- ------
# Alias start -> Start-Process
実行ファイルの検索
上記の例だとメモ帳を notepad
だけで指定していますが、メモ帳の実体は C:\WINDOWS\system32\notepad.exe
です。
ではなぜ前述のChromeの例や上記のメモ帳の例ではファイル名だけでアプリを起動できるのでしょうか?
まず拡張子の省略について、Microsoftのドキュメントに以下のような記載があります。
実行するコマンドで最初に使用されているトークンが、コマンドでも、拡張子を持つ既存のファイルへのファイル パスでもない場合は、Cmd.exe により、PATHEXT 環境変数の値を使用して、検索する拡張子とその順序が決定されます。 PATHEXT 変数の既定値は、.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC です。
つまり拡張子が省略された場合は .com
や .exe
とみなして検索されるみたいです。
次にディレクトリの省略について、Stackoverflowにまさにちょうど同じ内容の質問がありました。
ざっくり要約すると
Q. firefox.exeをどこでもstartで実行できるのはなんで?他の実行ファイルは親ディレクトリに移動しないと実行できないのに。
A. それは "App Paths" に追加されてるからだよ。これは環境変数を書き換えるよりも優れた方法なんだ。
という内容です。
ここで言及されている "App Paths" というのはレジストリ値で、以下に詳細が書かれています。
使い方としては "App Paths" 配下に実行ファイルのファイル名をサブキーとしたエントリを作成して、既定値に実行ファイルのフルパスを、Pathに親ディレクトリを設定するようです。
\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe
Property
(default) = C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Path = C:\Program Files (x86)\Google\Chrome\Application
気になる方は以下のコマンドをPowerShellで実行してみてください。現時点でどんな値が設定されているかを調べることができます。
@("HKCU", "HKLM") | % {
$rootKey = $_
Write-Host "${rootKey}"
$appPaths = (Get-Item "${rootKey}:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths")
$appPaths.GetSubKeyNames() | % {
$subKeyName = $_
Write-Host " ${subKeyName}"
$entry = (Get-Item "${rootKey}:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\${subKeyName}")
$entry.GetValueNames() | % {
$valueName = $_
$value = $entry.GetValue($valueName)
if ($valueName -eq "") {
$key = "(default)"
} else {
$key = $valueName
}
Write-Host " ${key} : ${value}"
}
}
}
出力結果のサンプル
HKCU
OneDriveFileLauncher.exe
SkipCloudDownload : 1
WindowsPackageManagerServer.exe
(default) : C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.21.3421.0_x64__8wekyb3d8bbwe\WindowsPackageManagerServer.exe
Path : C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.21.3421.0_x64__8wekyb3d8bbwe
winget.exe
(default) : C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.21.3421.0_x64__8wekyb3d8bbwe\winget.exe
Path : C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.21.3421.0_x64__8wekyb3d8bbwe
wt.exe
(default) : C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.18.2822.0_x64__8wekyb3d8bbwe\wt.exe
Path : C:\Program Files\WindowsApps\Microsoft.WindowsTerminal_1.18.2822.0_x64__8wekyb3d8bbwe
HKLM
7zFM.exe
(default) : C:\Program Files\7-Zip\7zFM.exe
Path : C:\Program Files\7-Zip\
:
:
chrome.exe
(default) : C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Path : C:\Program Files (x86)\Google\Chrome\Application
:
:
firefox.exe
(default) : C:\Program Files\Mozilla Firefox\firefox.exe
Path : C:\Program Files\Mozilla Firefox
:
:
startコマンドは環境変数の "Path" に設定されたディレクトリと "App Paths" に設定されたファイル一覧から実行ファイル検索するようです。
なのでChromeの場合は "App Paths" に chrome.exe
が設定されているので見つけることができ、メモ帳の場合は C:\WINDOWS\system32
が環境変数の "Path" に設定されているので見つけることができたというわけです。
startコマンドについては以上ですが、以下、関連する話もいくつかまとめてみました。
余談: 一時的な環境変数とエイリアス
各ブラウザは "App Paths" に値を設定していたのでパスを省略できていましたが、当然、環境変数に実行ファイルの親ディレクトリを追加することでもパスを省略できるようになります。
また、PowerShellにおいてはプロファイルを用いて一時的に環境変数に追記する、あるいはエイリアスを設定するという方法もあります。
# 方法1: 一時的に環境変数にパスを追加する
$env:Path += ";C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
# 方法2: エイリアスを設定する
Set-Alias chrome "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
この方法のメリットとして、例えば Excel や PowerPoint のようにコマンドラインオプションが存在するが環境変数にも "App Paths" にも設定されていないアプリを名前だけで呼び出すのに便利です。
Set-Alias excel "C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE"
Set-Alias powerpnt "C:\Program Files\Microsoft Office\root\Office16\POWERPNT.EXE"
Set-Alias winword "C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE"
コマンドプロンプトでもsetコマンド・doskeyコマンドで一時的な環境変数の変更やエイリアスの設定が可能です。
@rem 方法1: 一時的に環境変数にパスを追加する
set path=%path$;C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
@rem 方法2: エイリアスを設定する
doskey chrome="C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
余談: Chromeの起動オプション
そもそもなぜChromeをコマンドラインで実行したかったかというと、Chromeに起動オプションを指定して起動させたかったという背景があります。
Chromeの起動オプションについては以下が詳しいです。
自分がよく使うのは --incognito
と --app
の2つで、特に --app
に関しては任意のサイトやローカルファイルをPWAのようにアドレスバーのないウィンドウで表示する目的でよく使っています。
# シークレットモードで開く
chrome "https://qiita.com/" --incognito
# アプリケーションモードで開く
chrome --app="https://qiita.com/"
# ブラウザをシンプルなPDFビューアとして起動する
chrome --app="file:///C:/Users/tacos/Desktop/sample.pdf" --incognito
この使い方についてはいずれ記事にしたいと思っています。
あと、同じChrome系のEdgeも上記のオプションを使うことができます。Safari/Firefoxはごめんなさい、知りません。
余談: PowerShellからの呼び出し
startコマンドとは の節でstartコマンドはPowerShellからは直接実行できないといいましたが、間接的になら呼び出せます。
cmd.exeの /c
パラメータでコマンド文を渡して実行させることができるので、この機能を使います。
cmd /c "start chrome --app=`"https://qiita.com/`""
この方法であれば、仮にバージョンアップで C:\Program Files (x86)\Google\Chrome\Application
というパスが別物に変わってしまっても関係なくブラウザを起動させることができます。
さいごに
startコマンドがブラウザ名、ひいてはアプリ名だけで実行ファイルを実行できる理由について解説してみました。
自分は今までユーザ環境変数のPathやPowerShellプロファイルでブラウザのパスを通すようにしていたんですけど、これがあるならもうパスを通す必要ないかもですね。
ただ、Windowsの組み込みコマンドや "App Paths" が廃止になってしまう可能性もゼロではないので、そこは気をつけたいところです。
記事は以上になります。最後まで読んでくださりありがとうございます。