从Windows terminal里面的输出内容中截取trim IP 地址,再更新到.ssh/config文件里面

一、为什么要截取IP 地址(出发点)

bash 复制代码
PS C:\Users\yyy> & "D:\Program Files\google_cloude_cli\google-cloud-sdk\bin\gcloud.cmd" cloud-shell ssh
Automatic authentication with GCP CLI tools in Cloud Shell is disabled. To enable, please rerun command with --authorize-session flag.
Welcome to Cloud Shell! Type "help" to get started, or type "gemini" to try prompting with Gemini CLI.
Your Cloud Platform project in this session is set to vscode2gcloudshell.
Use gcloud config set project [PROJECT_ID] to change to a different project.
yyy@cloudshell:~ (vscode2gcloudshell)$ exit
logout
Connection to 34.10.33.28 closed

现在我能通过

bash 复制代码
& "D:\Program Files\google_cloude_cli\google-cloud-sdk\bin\gcloud.cmd" cloud-shell ssh

命令连接Google cloud shell,但是如果空闲20分钟,这个ip会变,我只能每次复制这个ip修改.ssh文件夹的config文件,然后我才能用vscode免配置(直接使用config里面的ssh host 信息)连接Google cloud shell进行开发,请问我怎么能在使用

bash 复制代码
& "D:\Program Files\google_cloude_cli\google-cloud-sdk\bin\gcloud.cmd" cloud-shell ssh

命令连接后,再输入exit,可以看到这个ip,然后自动把这个ip更新到.ssh文件下面的config文件呢

二、脚本实现

这是一个非常典型的痛点。

Google Cloud Shell 的 IP 是动态分配的,且闲置后会回收,导致本地 SSH 配置经常失效。

要实现"连接 -> 退出 -> 自动抓取 IP -> 更新 SSH Config",

最简单的办法是写一个 PowerShell 脚本 来封装这个流程。

目标自动化脚本会执行以下步骤:

  1. 打开 gcloud 连接(这会唤醒 Cloud Shell 实例)。
  2. 当你输入 exit 退出后,脚本自动获取当前活跃的连接信息。
  3. 使用正则表达式提取最新的 IP 地址。
  4. 自动替换 C:\Users\yyyy\.ssh\config 文件中的 IP。

解决方案:编写 PowerShell 自动化脚本

第一步:准备 SSH Config 文件

确保你的 C:\Users\yyyy\.ssh\config 文件中有一个专门用于 Google Cloud Shell 的 Host 配置,并且有一个占位符 IP。

文件内容示例:

ssh 复制代码
Host gcloud
    HostName 1.2.3.4
    User yyyy
    Port 6000
    IdentityFile ~/.ssh/google_compute_engine
    # 注意:HostName 这一行会被脚本自动修改,Host 的名字 "gcloud" 下面脚本要用到
第二步:创建脚本

在你的电脑上创建一个文件,例如 gcloud-connect.ps1,将以下代码复制进去:

powershell 复制代码
# 配置区域
$GcloudPath = "D:\Program Files\google_cloude_cli\google-cloud-sdk\bin\gcloud.cmd"
$SshConfigPath = "$env:USERPROFILE\.ssh\config"
$HostEntryName = "cloudshell" # Host 名称可以修改

# 1. 启动交互式连接
Write-Host "正在连接 Google Cloud Shell... (输入 exit 退出后将自动更新 IP)" -ForegroundColor Cyan
# 添加 --authorize-session 以解决报错中提到的认证警告
& $GcloudPath cloud-shell ssh --authorize-session

# 2. 连接结束后,获取最新的连接信息
Write-Host "`n连接已关闭,正在获取最新 IP 地址..." -ForegroundColor Yellow

# 使用 (| Out-String) 确保输出被视为单个字符串,而不是数组
$DryRunOutput = (& $GcloudPath cloud-shell ssh --dry-run 2>&1) | Out-String
# 数组 -match 正则:返回匹配的那一行内容,不填充 $matches。
# 字符串 -match 正则:返回 True/False,填充 $matches。
# Out-String 让PowerShell 把所有输出当作一个长字符串处理,会填充
# 强制将 gcloud 的输出转换为单个字符串对象,确保 -match 能正常工作并填充 $matches。
# 


# 3. 提取 IP 地址
# 匹配格式通常为 user@IP 或直接 IP,增加容错
if ($DryRunOutput -match '(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') {
    $NewIP = $matches[1]
    
    # 确保提取到了有效的 IP
    if ([string]::IsNullOrWhiteSpace($NewIP)) {
        Write-Error "错误:提取到的 IP 为空,跳过更新配置文件。"
        exit
    }

    Write-Host "检测到新 IP: $NewIP" -ForegroundColor Green

    # 4. 更新 SSH Config 文件
    if (Test-Path $SshConfigPath) {
        $Content = Get-Content $SshConfigPath
        $InHostBlock = $false
        $Updated = $false
        
        $NewContent = $Content | ForEach-Object {
            $Line = $_
            # 检测是否进入了目标 Host 块
            if ($Line -match "^Host\s+$HostEntryName$") {
                $InHostBlock = $true
            } elseif ($Line -match "^Host\s+") {
                $InHostBlock = $false
            }

            # 如果在目标块内,且是 HostName 行,则替换
            # 正则放宽,匹配 HostName 后可能没有参数的情况(修复你当前被写坏的文件)
            # 这里的正则匹配能处理可能的端口号干扰。
            if ($InHostBlock -and $Line -match "^\s*HostName\b") {
                $Updated = $true
                "    HostName $NewIP" # 输出新行
            } else {
                $Line # 输出原行
            }
        }

        if ($Updated) {
            $NewContent | Set-Content $SshConfigPath
            Write-Host "成功更新 $SshConfigPath 中的 HostName!" -ForegroundColor Cyan
            Write-Host "现在你可以直接在 VS Code 中连接 '$HostEntryName' 了。" -ForegroundColor Green
        } else {
            Write-Error "未在 config 文件中找到 Host 为 '$HostEntryName' 的 HostName 字段。"
        }
    } else {
        Write-Error "找不到 SSH Config 文件: $SshConfigPath"
    }
} else {
    Write-Error "无法解析 IP 地址,请检查 gcloud 输出。"
    Write-Host "调试信息 (Gcloud Output):"
    Write-Host $DryRunOutput
}
第三步:如何使用
  1. 打开 PowerShell。
  2. 运行这个脚本:.\gcloud-connect.ps1
  3. 它会像往常一样进入 Cloud Shell。
  4. 此时Cloud Shell 虚拟机被激活了。
  5. 输入 exit 退出。
  6. 脚本会提示 检测到新 IP: 34.x.x.x 并提示 成功更新...
  7. 打开 VS Code,直接连接 SSH Host gcloud 即可。

三、英语注释版本

bash 复制代码
# Configuration Section
$GcloudPath = "D:\Program Files\google_cloude_cli\google-cloud-sdk\bin\gcloud.cmd"
$SshConfigPath = "$env:USERPROFILE\.ssh\config"
$HostEntryName = "cloudshell" # Note: Changed to 'cloudshell' based on your error logs

# 1. Start interactive connection
Write-Host "Connecting to Google Cloud Shell... (Type 'exit' to quit, and the IP will update automatically)" -ForegroundColor Cyan
# Added --authorize-session to fix the authentication warning seen in your logs
& $GcloudPath cloud-shell ssh --authorize-session

# 2. After connection closes, retrieve latest connection info
Write-Host "`nConnection closed. Retrieving the latest IP address..." -ForegroundColor Yellow

# [Fix 1] Use (| Out-String) to ensure output is treated as a single string, not an array.
# This prevents the "Cannot index into a null array" error.
$DryRunOutput = (& $GcloudPath cloud-shell ssh --dry-run 2>&1) | Out-String

# 3. Extract IP address
# Matches format like user@IP or just the IP directly
if ($DryRunOutput -match '(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') {
    $NewIP = $matches[1]
    
    # [Fix 2] Ensure a valid IP was extracted before writing to file
    if ([string]::IsNullOrWhiteSpace($NewIP)) {
        Write-Error "Error: Extracted IP is empty. Skipping config update."
        exit
    }

    Write-Host "New IP detected: $NewIP" -ForegroundColor Green

    # 4. Update SSH Config file
    if (Test-Path $SshConfigPath) {
        $Content = Get-Content $SshConfigPath
        $InHostBlock = $false
        $Updated = $false
        
        $NewContent = $Content | ForEach-Object {
            $Line = $_
            # Check if we entered the target Host block
            if ($Line -match "^Host\s+$HostEntryName$") {
                $InHostBlock = $true
            } elseif ($Line -match "^Host\s+") {
                $InHostBlock = $false
            }

            # If inside the target block and it is a HostName line, replace it
            # [Fix 3] Relaxed regex to match HostName even if empty (fixes your currently broken config file)
            if ($InHostBlock -and $Line -match "^\s*HostName\b") {
                $Updated = $true
                "    HostName $NewIP" # Output new line
            } else {
                $Line # Output original line
            }
        }

        if ($Updated) {
            $NewContent | Set-Content $SshConfigPath
            Write-Host "Successfully updated HostName in $SshConfigPath!" -ForegroundColor Cyan
            Write-Host "You can now connect to '$HostEntryName' directly in VS Code." -ForegroundColor Green
        } else {
            Write-Error "HostName field for Host '$HostEntryName' not found in the config file."
        }
    } else {
        Write-Error "SSH Config file not found: $SshConfigPath"
    }
} else {
    Write-Error "Unable to parse IP address. Please check gcloud output."
    Write-Host "Debug Info (Gcloud Output):"
    Write-Host $DryRunOutput
}
相关推荐
我不是懒洋洋15 小时前
预处理详解
c语言·开发语言·c++·windows·microsoft·青少年编程·visual studio
人工智能训练16 小时前
从 1.1.3 到 1.13.2!Ubuntu 24.04 上 Dify 升级保姆级教程(零数据丢失 + 一键迁移)
linux·运维·人工智能·windows·ubuntu·dify
mldlds16 小时前
Windows安装Redis图文教程
数据库·windows·redis
softbangong17 小时前
815-批量Excel文件合并工具,批量excel文件、工作表合并软件
linux·windows·excel·文件合并·excel合并·数据整理
烛之武17 小时前
Nacos3.2.0下载安装教程(Windows版本)
windows
liulilittle17 小时前
OPENPPP2 sysnat loader implement / C/C++
服务器·c语言·开发语言·网络·c++·tcp/ip
竹之却18 小时前
【OpenClaw】云服务器端 openclaw 集成本地 Windows端 ollama 模型
windows·llama·ollama·openclaw·qwen3.5
cnnews18 小时前
手机通过Termux安装unbuntu,开启SSH
linux·运维·ubuntu·ssh
阿昭L18 小时前
Windows通用的C/C++工程CMakeLists
c语言·c++·windows·makefile·cmake
公子小六18 小时前
基于.NET的Windows窗体编程之WinForms控件简介
windows·microsoft·c#·.net