$4 blog
GNU/Linux, Debian/Ubuntu, Free Software/Open Source Software, and Programming.
2025年9月5日 星期五
想算數字裡有幾個 1?C++, Python3, Go, Rust 大亂鬥!
2025年9月2日 星期二
C++/Python3/Go/Rust 關於 list/array/vector 的 sort 在設計上的不同差異
2025年6月30日 星期一
演算法的逆襲:為何 O(N log N) 的排序,有時竟能擊敗 O(N) 的雜湊?
2025年6月29日 星期日
在 Rust 上又遇到了一次跟 C++ 一樣的問題
透過 BROWSER 環境變數在 headless server 上搞定 Gemini CLI 的 Google 登入
嘿,各位開發者!如果你也嘗試在沒有圖形介面的伺服器上使用 npm install -g @google/gemini-cli,並希望透過 Google 帳號登入,你可能遇到了一個小麻煩:「沒有網址讓我連過去認證!」
別擔心,這篇文章將帶你一步步解決這個問題,讓你能在伺服器上順利使用 Gemini CLI。
問題根源:無頭環境的挑戰
當你在本地電腦使用 Google 登入時,CLI 會自動開啟瀏覽器讓你完成認證。但在伺服器這種「無頭 (headless)」環境,它根本沒辦法開啟瀏覽器。這導致了認證流程的中斷。
我們要做的,就是**「欺騙」CLI**,讓它以為有個瀏覽器會幫它處理網址,但實際上我們只是把認證網址攔截下來,然後手動到自己的電腦上完成登入。
步驟一:讓 CLI「吐出」認證網址
首先,我們需要一個簡單的 Shell 指令碼,來捕捉 Gemini CLI 嘗試開啟的認證網址。
-
建立 url-logger.sh 指令碼:
在你的伺服器上,建立一個新檔案,例如放在 /usr/local/bin/url-logger.sh。
nano /usr/local/bin/url-logger.sh
然後貼上以下內容:
#!/bin/bash # 這個指令碼會將 Gemini CLI 嘗試開啟的網址記錄下來 # 認證網址將被寫入這個檔案 URL_FILE="$HOME/gemini_auth_url.txt" # 確保檔案存在 touch "$URL_FILE" # 將網址和時間戳記附加到檔案中 echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$URL_FILE" # 同時印出到終端機,方便查看 echo "URL would be opened: $1"
-
賦予執行權限:
讓這個指令碼可執行。
chmod +x /usr/local/bin/url-logger.sh
步驟二:設定 BROWSER 環境變數
接下來,我們要告訴系統,當任何程式(包括 Gemini CLI)嘗試開啟瀏覽器時,都執行我們剛才建立的 url-logger.sh 指令碼。
-
編輯你的 Shell 設定檔:
這通常是 ~/.bashrc (如果你用 Bash) 或 ~/.zshrc (如果你用 Zsh)。
# 例如: nano ~/.bashrc
-
添加 BROWSER 環境變數:
在檔案的任何位置,加入這行。請確保路徑是 url-logger.sh 的實際存放位置。
export BROWSER=/usr/local/bin/url-logger.sh
-
儲存並重新載入設定:
儲存檔案後,執行 source ~/.bashrc (或 source ~/.zshrc),或者直接關閉並重新開啟你的 SSH 連線,讓設定生效。
步驟三:啟動 Gemini CLI 並獲取認證網址
現在,萬事俱備!我們可以啟動 Gemini CLI 並開始認證流程了。
-
啟動 Gemini CLI:
gemini
進入互動式介面後,輸入 /auth,然後選擇 "Login with Google"。
-
檢查認證網址檔案:
此時,gemini 不會開啟任何視窗,而是把認證網址寫入到我們指定的檔案中。你可以用 cat 命令查看:
cat "$HOME/gemini_auth_url.txt"
你會看到一串類似 https://accounts.google.com/o/oauth2/v2/auth?client_id=... 的超長網址。請完整複製這串網址!
步驟四:在本地電腦完成 Google 認證
現在,輪到你的本地電腦出場了!
-
在本地瀏覽器開啟網址:
把你剛才從伺服器上複製的完整認證網址,貼到你本地電腦的網頁瀏覽器中,然後打開它。
-
完成 Google 登入和授權:
按照 Google 頁面的指示,用你的 Google 帳號登入並授權。完成後,瀏覽器會嘗試跳轉到一個類似 http://localhost:PORT/oauth2callback?code=YOUR_CODE... 的網址。這個頁面會顯示「此網站無法連線」之類的錯誤,這是完全正常的!
步驟五:將 localhost 回調傳回伺服器
這是最關鍵的一步!我們要將本地瀏覽器嘗試跳轉的 localhost 網址(即使它報錯了),再傳回給伺服器上的 gemini CLI。
-
複製 localhost 回調網址:
從你本地瀏覽器的網址列上,完整複製那個 http://localhost:PORT/oauth2callback?... 的網址。務必包含所有的參數!
-
在伺服器上執行 curl 命令:
回到你的伺服器終端機,執行以下 curl 命令,將雙引號內的內容替換成你剛才複製的完整 localhost 網址:
curl "http://localhost:YOUR_PORT/oauth2callback?code=YOUR_CODE&scope=..."
例如:
curl "http://localhost:21165/oauth2callback?code=4/0xxxxxxxxxxxxxxxxx&scope=https://www.googleapis.com/auth/userinfo.email..."
執行完 curl 後,你會看到伺服器上的 gemini CLI 互動介面會顯示認證成功的訊息。恭喜你!
搞定!還有更好的選擇嗎?
你已經成功在無頭伺服器上搞定了 Gemini CLI 的 Google 帳號登入!這證明了只要掌握方法,多麼棘手的環境問題都能克服。
不過,對於長期或自動化用途,我仍然會強烈推薦使用服務帳戶 (Service Account) 進行認證。服務帳戶提供更高的安全性,而且完全不需要人工介入,對於伺服器應用來說是更優雅的解決方案。你可以參考官方文件或相關教學,了解如何建立和使用 Google Cloud 服務帳戶金鑰。
希望這篇文章對你有幫助!Happy coding!
以上內容由 Gemini AI 整理 Gemini CLI 伺服器設定指南 對話內容產出。
2024年12月15日 星期日
C++17 好用的 tuple 的 auto 解構
#include <iostream>
#include <vector>
#include <tuple>
using namespace std;
int main()
{
vector<tuple<int,int,double>> box;
for (int i{1}; i < 10; ++i)
box.push_back(make_tuple(i, i*i, (double)i/(i*i)));
for (auto [idx, square, value]: box)
cout << idx << " " << square << " " << value << endl;
while (!box.empty()) {
auto [idx, square, value] = box.back();
box.pop_back();
cout << idx << " " << square << " " << value << endl;
}
return 0;
}
2024年11月29日 星期五
C++ 的 std::string::size() 使用上要小心的地方
std::string::size() 的回傳會是 size_t 這樣的無號正整數或零的型別。
我在刷 LeetCode 的題目時寫出了這樣的程式碼。
class Solution { public: int strStr(string haystack, string needle) { for (int i = 0; i <= haystack.size() - needle.size(); i++) { // ... } return -1; } };
當 needle 比 haystack 還要長時,其運算結果原以為會是負數,但是因為無號正整數或零的型別,就會被轉成正整數,導致 for 迴圈中會透過 i 去使用到 haystack 或是 needle 以外的記憶體位址,導致程式崩潰。