如何在 WSL 中,用 PhpStorm 指令開啟 WSL 系統中的專案
我自己平常開發時常用的作業系統是 Mac 和 WSL (Windows Subsystem for Linux),而在編寫 PHP 時都是使用 PhpStorm 這款超級好用的 IDE。
在 Mac 作業系統上,PhpStorm 提供了一個方便的功能,可以在終端機中使用 phpstorm
命令來打開專案。
$ cd /path/to/project
$ phpstorm .
這個功能在 Windows 中也有提供。
# 使用 Toolbox 安裝 PhpStorm 的話,可以在 CMD 或是 PowerShell 中使用這個指令開啟專案
PhpStorm.cmd .
雖然 PhpStorm 支援開啟在 WSL 中的檔案,但並不支援使用指令開啟檔案,雖然這不影響開發,但能直接在 Terminal 中打開專案還是很方便。於是我上網查找是否有解決辦法。
這個問題有在 JetBrains 的論壇中有人提出來過,有人提供了一個解法,使用跨檔案系統工作功能,讓你在 WSL 中執行 Windows 程式。
# .bashrc or .zshrc
phpstorm() {
cmd.exe "/mnt/c/Users/<username>/scripts/jetbrains/phpstorm.cmd" $(wslpath -w ${1:-$(pwd)})
}
我們可以在 WSL 中訪問 Winodws 系統中的資料夾,例如 C:\\
在 WSL 中會以 /mnt/c
表示。而如果想要在 WSL 中 執行 Windows 系統的程式,可以使用 cmd.exe
來執行該程式。
wslpath
的功能類似 pwd
,可以取得當前在 WSL 中的路徑,並可以選擇以 Linux 或是 Windows 的格式來呈現。
$ wslpath
wslpath: Invalid argument
Usage:
-a force result to absolute path format
-u translate from a Windows path to a WSL path (default)
-w translate from a WSL path to a Windows path
-m translate from a WSL path to a Windows path, with '/' instead of '\\'
EX: wslpath 'c:\\users'
所以如果我想取得 Winodws 格式的當前路徑,可以使用 wslpath -w .
。
那 ${1:-$(pwd)}
這一段是什麼意思呢?
${1:-$(pwd)}
是一個 shell script 的語法,表示如果有傳入第一個參數就使用該參數,否則使用 pwd
指令執行的的輸出。
$()
中可以放入一個指令,這個指令會在整個指令執行前先執行並返回結果,如下所示。
cd /path/to/what/i/want
# My current path is /path/to/what/i/want
echo "My current path is $(pwd)"
假設我輸入 phpstorm .
那麼 ${1}
就會是 .
,如果沒有輸入,就會使用 pwd 的執行輸出,也就是當前完整的目錄。
因為我是使用 Toolbox 安裝 PhpStorm,所以路徑需要稍微修改一下。
# .bashrc or .zshrc
phpstorm() {
cmd.exe '/mnt/c/Users/<username>/AppData/Local/JetBrains/Toolbox/scripts/PhpStorm.cmd' $(wslpath -w ${1:-$(pwd)})
}
成功使用 PhpStorm 開啟專案!
But
我發現了幾件事情,首先指令執行之後,會在 WSL 中開啟一個 Non-Daemon Process,你可以看到圖片中啟動 PhpStorm 後,我們就沒辦法與 Terminal 繼續互動了,直到把 PhpStorm 關閉為止。
你可以使用
kill <pid>
的方式結束這個 Process,PhpStorm 並不會因此關閉。如果不想看到執行後顯示的訊息,並且讓 Process 以 Daemon 的方式在背景執行的話,可以在指令後面加上
> /dev/null 2>&1 &
。
再來是 WSL 的根目錄路徑其實有變更,新版本的路徑如下。
# 新版本的根目錄路徑
\\wsl.localhost\Ubuntu\
但 PhpStorm 仍舊是使用舊版本的路徑。
# 舊版本的根目錄路徑
\\wsl$\Ubuntu\
可以用 PhpStorm 的 File → Open 查看開啟的路徑
有關於系統路徑的變更,可以查看微軟的這篇文章。目前新與舊版本的系統路徑都能夠使用,但我想未來 PhpStorm 更新預設也會使用新的路徑。
如果想用舊的路徑,該怎麼辦?
可以嘗試修改下面這段。
$(wslpath -w ${1:-$(pwd)})
我第一個想法是使用串接字串,因為舊路徑前半段的 \\\\wsl$\\Ubuntu
是固定的,後半段我們只要補上 pwd
的輸出結果就好,但是 pwd
的結果是使用斜線 /
,與 Windows 的反斜線 \\
不同。
$ pwd
/home/allen
所以串接起來就會不對。
$ echo '\\\\wsl$\\Ubuntu'$(pwd)
\\wsl$\Ubuntu/home/allen
嘗試問問 ChatGPT 有沒有什麼方法可以把字串中的斜線轉成反斜線,他很快速地給我了一個答案。
string="/home/allen"
new_string="${string//\//\\}"
echo "$new_string"
但輸出的結果是。
\homellen
\a
是響鈴符號,如果你輸入 echo "\a"
的話,並不會看到任何輸出,而是聽到喇叭發出 "噔" 的一聲。
看樣子 ChatGPT 也逃不了被跳脫字元坑到的命運🥲。
知道了 Shell Script 替換字元的方式之後,稍微修改一下 phpstorm()
的內容。
# .bashrc or .zshrc
phpstorm() {
# 使用 realpath 取得完整的路徑
# 沒有傳入參數就使用 pwd 取得當前的路徑
string=$(realpath ${1:-$(pwd)})
target='/'
replace='\'
cmd.exe 'windows/path/to/PhpStorm.cmd' '\\\\wsl$\\Ubuntu'${string//$target/$replace}
}
同樣也能成功開啟資料夾,且路徑顯示舊有的路徑。
美中不足
稍微試用了一下,還是有一些問題,如果你因為安裝 (移除) 套件而重新啟動 PhpStorm 的話,重新開啟後就會將所有 Recent Projects 全部打開。
然後有機會 Crash
測試了一個解決辦法是,在啟動 PhpStorm 之後,就將 WSL 中的 Daemon Process 終止。
phpstorm() {
cmd.exe 'windows/path/to/PhpStorm.cmd' $(wslpath -w ${1:-$(pwd)}) >/dev/null 2>&1 &
# 取得 PID
PID=$!
# 等待 PhpStorm 啟動
sleep 10
# 終止 PhpStorm 在 WSL 中的 Daemon Process
kill $PID
}
雖然重新啟動後還是會開啟所有的 Recent Projects,但並不會因此 Crash。
避免開啟所有 Recent Projects
可以在 Appearance & Behavior → System Settings 的頁面關閉 Reopen projects on startup 的功能。