提交 2d9524be authored 作者: 陈泽健's avatar 陈泽健

fix(shell): 解决模块化拆分后IP和NTP检测脚本执行错误,补充数据库备份的库名

- 使用临时文件避免SSH输出截断问题
- 移除Shell脚本中的exec 2>/dev/null以显示错误信息
- 修复JSON输出被截断导致解析失败的问题
- 改进Invoke-RemoteShellCheck函数错误处理
- 为config_check.sh和ntp_check.sh添加common.sh加载容错机制
- 通过base64编码安全传输脚本输出内容
上级 535ebe7a
......@@ -471,29 +471,55 @@ function Invoke-RemoteShellCheck {
return $null
}
# 执行脚本(使用2>/dev/null抑制错误输出)
$cmd = "cd $RemotePath 2>/dev/null && chmod +x common.sh $ScriptName 2>/dev/null && ./$ScriptName $Arguments 2>/dev/null"
$result = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
# 检查执行结果
if (-not $result) {
Write-Log -Level "ERROR" -Message "[SHELL] SSH命令执行失败: $ScriptName"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -rf $RemotePath 2>/dev/null" | Out-Null
return $null
}
# 检查输出
if (-not $result.Output) {
Write-Log -Level "WARN" -Message "[SHELL] 脚本未返回输出: $ScriptName (退出码: $($result.ExitCode))"
# 执行脚本并将输出保存到临时文件,然后使用base64编码传输
$outputFile = "/tmp/health_check_output.txt"
$base64File = "/tmp/health_check_output.b64"
$cmd = "cd $RemotePath && chmod +x common.sh $ScriptName && ./$ScriptName $Arguments > $outputFile 2>&1 && base64 -w 0 $outputFile > $base64File && rm -f $outputFile"
$execResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
# 使用pscp下载base64编码的文件(更可靠)
$localTempDir = Join-Path $env:TEMP "health_check"
if (-not (Test-Path $localTempDir)) {
New-Item -ItemType Directory -Path $localTempDir -Force | Out-Null
}
$localBase64File = Join-Path $localTempDir "output.b64"
$downloadSuccess = $false
if ($global:PSCP_PATH -and (Test-Path $global:PSCP_PATH)) {
$pscpArgs = @(
"-P", $Server.Port,
"-l", $Server.User,
"-pw", $Server.Pass,
"-batch",
"$($Server.User)@$($Server.IP):$base64File",
$localBase64File
)
$pscpOutput = & $global:PSCP_PATH @pscpArgs 2>&1
$downloadSuccess = (Test-Path $localBase64File) -and ((Get-Item $localBase64File).Length -gt 0)
}
# 清理临时文件
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -rf $RemotePath 2>/dev/null" | Out-Null
# 清理远程临时文件和目录
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -f $base64File; rm -rf $RemotePath" | Out-Null
# 返回结果
if ($result.Output) {
return $result.Output -join "`n"
if ($downloadSuccess -and (Test-Path $localBase64File)) {
try {
$base64Content = Get-Content $localBase64File -Raw
$decodedContent = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($base64Content))
Remove-Item $localBase64File -Force -ErrorAction SilentlyContinue
Remove-Item $localTempDir -Force -ErrorAction SilentlyContinue
return $decodedContent
} catch {
Write-Log -Level "ERROR" -Message "[SHELL] Base64解码失败: $($_.Exception.Message)"
Remove-Item $localBase64File -Force -ErrorAction SilentlyContinue
Remove-Item $localTempDir -Force -ErrorAction SilentlyContinue
return $null
}
} else {
# 如果下载失败,返回null
Write-Log -Level "WARN" -Message "[SHELL] 无法下载输出文件: $ScriptName"
Remove-Item $localTempDir -Force -ErrorAction SilentlyContinue
return $null
}
}
......
......@@ -30,7 +30,23 @@
# 加载基础函数库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/common.sh"
# 尝试加载common.sh,如果失败则输出错误
if [ -f "${SCRIPT_DIR}/common.sh" ]; then
source "${SCRIPT_DIR}/common.sh"
else
# 如果common.sh不存在,定义最基本的函数
json_kv() {
local key="$1"
local value="$2"
local is_last="${3:-false}"
if [ "$is_last" = "true" ]; then
echo " \"$key\": \"$value\""
else
echo " \"$key\": \"$value\","
fi
}
fi
# ================================
# 参数解析
......@@ -281,6 +297,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -192,6 +192,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -222,6 +222,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -205,6 +205,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -310,6 +310,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -28,7 +28,22 @@
# 加载基础函数库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/common.sh"
# 尝试加载common.sh,如果失败则定义基本函数
if [ -f "${SCRIPT_DIR}/common.sh" ]; then
source "${SCRIPT_DIR}/common.sh"
else
json_kv() {
local key="$1"
local value="$2"
local is_last="${3:-false}"
if [ "$is_last" = "true" ]; then
echo " \"$key\": \"$value\""
else
echo " \"$key\": \"$value\","
fi
}
fi
# ================================
# 参数解析
......@@ -199,6 +214,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -30,7 +30,22 @@
# 加载基础函数库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/common.sh"
# 尝试加载common.sh,如果失败则定义基本函数
if [ -f "${SCRIPT_DIR}/common.sh" ]; then
source "${SCRIPT_DIR}/common.sh"
else
json_kv() {
local key="$1"
local value="$2"
local is_last="${3:-false}"
if [ "$is_last" = "true" ]; then
echo " \"$key\": \"$value\""
else
echo " \"$key\": \"$value\","
fi
}
fi
# ================================
# 参数解析
......@@ -316,6 +331,4 @@ main() {
}
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
......@@ -23,6 +23,18 @@ ConvertFrom-ShellJson : 无法将参数绑定到参数“JsonString”,因为
```
### 1.2 问题二:Shell脚本未返回任何输出
```ignorelang
[2026-05-13 15:24:40] [INFO] ========== 开始配置IP检测 (Shell模式) ==========
[2026-05-13 15:24:40] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test-module\pscp.exe
[2026-05-13 15:24:40] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test-module\lib\shell\common.sh -> root@192.168.5.46:/tmp/health_check/
[2026-05-13 15:24:40] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test-module\pscp.exe
[2026-05-13 15:24:41] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test-module\lib\shell\config_check.sh -> root@192.168.5.46:/tmp/health_check/
[2026-05-13 15:24:41] [WARN] [SHELL] 脚本未返回输出: config_check.sh (退出码: 2)
[2026-05-13 15:24:41] [ERROR] [SHELL] Shell脚本未返回任何输出
[2026-05-13 15:24:41] [ERROR] [配置] Shell脚本执行失败
[2026-05-13 15:24:41] [INFO] ========== 结束检测配置文件 IP ==========
```
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
......
# _PRD_模块化拆分后IP检测脚本执行错误_问题处理 - 计划执行文档
> 创建时间:2026-05-13
> 更新时间:2026-05-13(补充问题二修复)
> 状态:已完成
> 来源:`Docs/PRD/服务自检/问题修复/_PRD_模块化拆分后IP检测脚本执行错误_问题处理.md`
......@@ -9,11 +10,14 @@
## 1. 问题分析
### 1.1 核心问题
IP检测Shell脚本执行时返回空输出,导致PowerShell参数验证失败。
IP检测Shell脚本执行时出现多个错误:
1. **空输出导致参数验证失败**:脚本返回空输出
2. **脚本执行失败退出码2**`exec 2>/dev/null` 隐藏了错误信息
### 1.2 错误详情
#### 问题:空输出导致参数验证失败
#### 问题:空输出导致参数验证失败
```
ConvertFrom-ShellJson : 无法将参数绑定到参数"JsonString",因为该参数为空字符串。
```
......@@ -23,6 +27,17 @@ ConvertFrom-ShellJson : 无法将参数绑定到参数"JsonString",因为该
2. `ConvertFrom-ShellJson` 参数设置为 `Mandatory=$true`
3. 空字符串无法通过参数验证
#### 问题二:Shell脚本未返回任何输出(新增)
```
[WARN] [SHELL] 脚本未返回输出: config_check.sh (退出码: 2)
[ERROR] [SHELL] Shell脚本未返回任何输出
```
**原因分析**
1. `exec 2>/dev/null` 导致所有错误信息被隐藏
2. 脚本执行失败但无法看到错误原因
3. 退出码2表示语法错误或命令执行失败
---
## 2. 解决方案
......@@ -58,9 +73,9 @@ if ([string]::IsNullOrEmpty($JsonString)) {
**位置**`Invoke-RemoteShellCheck` 函数
**改进内容**
- 添加执行结果检查
- 添加空输出警告日志
- 显示退出码信息
- 使用临时文件避免输出截断
- 将stderr合并到stdout以便调试
- 改进错误日志输出
### 2.3 改进config_check.sh脚本
......@@ -70,7 +85,14 @@ if ([string]::IsNullOrEmpty($JsonString)) {
**改进内容**
- 确保PLATFORM变量始终有值
- 为config_count和total_ips设置默认值
- 添加默认值处理
- 移除 `exec 2>/dev/null` 以便调试
### 2.4 移除Shell脚本中的exec 2>/dev/null
**原因**
- `exec 2>/dev/null` 会导致错误信息被隐藏
- 影响调试和问题定位
- 已在SSH命令中使用 `2>&1` 合并stderr
---
......@@ -100,29 +122,30 @@ function ConvertFrom-ShellJson {
}
```
### 3.2 Invoke-RemoteShellCheck 函数
### 3.2 Invoke-RemoteShellCheck 函数(关键修复)
**修改内容**
添加更详细的错误日志和空输出检查
使用临时文件避免输出截断,并保留错误信息
**代码变更**
```powershell
# 检查执行结果
if (-not $result) {
Write-Log -Level "ERROR" -Message "[SHELL] SSH命令执行失败: $ScriptName"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -rf $RemotePath 2>/dev/null" | Out-Null
return $null
}
# 执行脚本并将输出保存到临时文件(避免输出被截断)
$outputFile = "/tmp/health_check_output_$ScriptName.json"
$cmd = "cd $RemotePath && chmod +x common.sh $ScriptName && ./$ScriptName $Arguments > $outputFile 2>&1; cat $outputFile; rm -f $outputFile"
$result = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
# 检查输出
if (-not $result.Output) {
Write-Log -Level "WARN" -Message "[SHELL] 脚本未返回输出: $ScriptName (退出码: $($result.ExitCode))"
}
# 清理临时文件
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -rf $RemotePath" | Out-Null
# ... 返回结果
# 检查输出并返回结果
if ($result.Output) {
return $result.Output -join "`n"
if ($result.Output -is [array]) {
return $result.Output -join "`n"
} else {
return $result.Output.ToString()
}
} else {
Write-Log -Level "WARN" -Message "[SHELL] 脚本未返回输出: $ScriptName (退出码: $($result.ExitCode))"
return $null
}
```
......@@ -157,6 +180,31 @@ output_json() {
}
```
### 3.4 所有Shell脚本移除exec 2>/dev/null
**受影响文件**
- `lib/shell/resource_check.sh`
- `lib/shell/java_check.sh`
- `lib/shell/docker_check.sh`
- `lib/shell/middleware_check.sh`
- `lib/shell/dns_check.sh`
- `lib/shell/ntp_check.sh`
- `lib/shell/config_check.sh`
**修改前**
```bash
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
```
**修改后**
```bash
# 执行主函数
main
```
---
## 4. 测试验证
......@@ -168,6 +216,7 @@ output_json() {
| 正常输出 | 配置文件存在 | 成功返回JSON |
| 空输出 | 无配置文件 | 返回默认JSON而不是null |
| 参数验证 | 传入空字符串 | 显示错误日志,不崩溃 |
| 错误可见性 | 脚本执行失败 | 显示错误信息而非静默失败 |
### 4.2 验证步骤
......@@ -176,6 +225,7 @@ output_json() {
3. 输入服务器连接信息
4. 观察配置IP检测输出
5. 确认无参数验证错误
6. 如有错误,确认能看到错误信息
---
......@@ -199,7 +249,26 @@ output_json() {
| 1 | 修复ConvertFrom-ShellJson参数验证 | ✅ 已完成 |
| 2 | 添加空输入检查 | ✅ 已完成 |
| 3 | 改进Invoke-RemoteShellCheck错误处理 | ✅ 已完成 |
| 4 | config_check.sh添加默认值处理 | ✅ 已完成 |
| 4 | 使用临时文件避免输出截断 | ✅ 已完成 |
| 5 | config_check.sh添加默认值处理 | ✅ 已完成 |
| 6 | 移除Shell脚本中的exec 2>/dev/null | ✅ 已完成 |
---
## 7. 问题二补充说明
### 7.1 问题分析
脚本执行失败返回退出码2,但由于 `exec 2>/dev/null`,所有错误信息被隐藏,无法知道失败原因。
### 7.2 解决方案
- 移除 `exec 2>/dev/null`
- 在SSH命令中使用 `2>&1` 将stderr合并到stdout
- 将输出保存到临时文件,确保完整捕获
### 7.3 技术要点
- 退出码2通常表示:语法错误、命令不存在、权限问题
- 通过将stderr合并到stdout,可以看到完整的错误信息
- 使用临时文件可以避免输出被截断
---
......
......@@ -32,6 +32,26 @@ Write-Log : 无法对参数“Level”执行参数验证。参数“DEBUG”不
```
### 1.2 问题二:JSON解析失败
```ignorelang
[2026-05-13 15:25:14] [INFO] ========== 开始NTP检测 (Shell模式) ==========
[2026-05-13 15:25:14] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test-module\pscp.exe
[2026-05-13 15:25:15] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test-module\lib\shell\common.sh -> root@192.168.5.46:/tmp/health_check/
[2026-05-13 15:25:15] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test-module\pscp.exe
[2026-05-13 15:25:15] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test-module\lib\shell\ntp_check.sh -> root@192.168.5.46:/tmp/health_check/
[2026-05-13 15:25:16] [ERROR] [SHELL] JSON解析失败: 无效的 JSON 基元: 。
[2026-05-13 15:25:16] [INFO] [SHELL] 原始输出前200字符: {
"check_type": "ntp_check",
"timestamp": "2026-05-13 15:25:15",
"ntp_service": "chronyd",
"service_status": "running",
"time_sync_status": "synchronized",
"ntp_servers": "ntp1.aliyun.com,
[2026-05-13 15:25:16] [ERROR] [NTP] Shell脚本执行失败
[2026-05-13 15:25:16] [INFO] NTP 服务检测完成.
[2026-05-13 15:25:16] [INFO] ========== 结束检测NTP服务 ==========
```
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
......
# _PRD_模块化拆分后NTP检测脚本执行错误_问题处理 - 计划执行文档
> 创建时间:2026-05-13
> 更新时间:2026-05-13(补充问题二修复)
> 状态:已完成
> 来源:`Docs/PRD/服务自检/问题修复/_PRD_模块化拆分后NTP检测脚本执行错误_问题处理.md`
......@@ -9,20 +10,17 @@
## 1. 问题分析
### 1.1 核心问题
NTP检测Shell脚本输出的JSON格式错误,导致PowerShell解析失败。
NTP检测Shell脚本执行时出现多个错误:
1. **JSON格式错误**`ntp_servers` 字段值包含双层引号
2. **JSON输出被截断**:plink.exe输出在 `ntp_servers` 值中间被截断
### 1.2 错误详情
#### 问题:JSON格式错误 - 双引号嵌套
#### 问题:JSON格式错误 - 双引号嵌套
```
[SHELL] JSON解析失败: 传入的对象无效,应为":"或"}"。 (186): {
"check_type": "ntp_check",
"timestamp": "2026-05-13 15:00:00",
"ntp_service": "chronyd",
"service_status": "running",
"time_sync_status": "synchronized",
"ntp_servers": ""ntp1.aliyun.com,ntp2.aliyun.com,ntp3.aliyun.com"",
"time_offset": "N/A",
}
```
......@@ -36,6 +34,22 @@ NTP检测Shell脚本输出的JSON格式错误,导致PowerShell解析失败。
json_kv "ntp_servers" "\"$ntp_servers\""
```
#### 问题二:JSON输出被截断(新增)
```
{
"check_type": "ntp_check",
"timestamp": "2026-05-13 15:25:15",
"ntp_service": "chronyd",
"service_status": "running",
"time_sync_status": "synchronized",
"ntp_servers": "ntp1.aliyun.com,
```
**原因分析**
- plink.exe输出缓冲区限制
- SSH命令输出在长值处被截断
- `exec 2>/dev/null` 导致错误被隐藏
---
## 2. 解决方案
......@@ -60,35 +74,31 @@ json_kv "ntp_servers" "$ntp_servers"
- 不需要手动在调用时添加引号
- 移除多余的 `\` 和 `"` 即可
### 2.2 json_kv函数说明
### 2.2 改进Invoke-RemoteShellCheck避免输出截断
**函数定义**(common.sh):
```bash
json_kv() {
local key="$1"
local value="$2"
local is_last="${3:-false}"
if [ "$is_last" = "true" ]; then
echo " \"$key\": \"$value\""
else
echo " \"$key\": \"$value\","
fi
}
```
**正确用法**:
```bash
# 字符串值 - json_kv会自动添加引号
json_kv "name" "value"
**文件**:`check_server_health.ps1`
**位置**:`Invoke-RemoteShellCheck` 函数
# 带逗号分隔的字符串 - 直接传值即可
json_kv "servers" "server1,server2,server3"
**修复方案**:
- 将脚本输出先保存到临时文件,再读取
- 避免 SSH 输出缓冲区限制
- 移除 `exec 2>/dev/null` 避免隐藏错误
# 数字值 - 也被当作字符串处理
json_kv "port" "8080"
**修改后**:
```powershell
# 执行脚本并将输出保存到临时文件(避免输出被截断)
$outputFile = "/tmp/health_check_output_$ScriptName.json"
$cmd = "cd $RemotePath && chmod +x common.sh $ScriptName && ./$ScriptName $Arguments > $outputFile 2>&1; cat $outputFile; rm -f $outputFile"
$result = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
```
### 2.3 移除Shell脚本中的exec 2>/dev/null
**原因**:
- `exec 2>/dev/null` 会导致错误信息被隐藏
- 影响调试和问题定位
- 已在SSH命令中使用 `2>&1` 合并stderr
---
## 3. 代码修改详情
......@@ -123,6 +133,50 @@ json_kv "time_offset" "$time_offset" false
echo "}"
```
### 3.2 Invoke-RemoteShellCheck 函数(关键修复)
**修改内容**:
使用临时文件避免输出截断
**代码变更**:
```powershell
# 执行脚本并将输出保存到临时文件(避免输出被截断)
$outputFile = "/tmp/health_check_output_$ScriptName.json"
$cmd = "cd $RemotePath && chmod +x common.sh $ScriptName && ./$ScriptName $Arguments > $outputFile 2>&1; cat $outputFile; rm -f $outputFile"
$result = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
# 清理临时文件
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -rf $RemotePath" | Out-Null
# 检查输出并返回结果
if ($result.Output) {
if ($result.Output -is [array]) {
return $result.Output -join "`n"
} else {
return $result.Output.ToString()
}
} else {
Write-Log -Level "WARN" -Message "[SHELL] 脚本未返回输出: $ScriptName (退出码: $($result.ExitCode))"
return $null
}
```
### 3.3 ntp_check.sh 移除exec 2>/dev/null
**修改前**:
```bash
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
```
**修改后**:
```bash
# 执行主函数
main
```
---
## 4. 输出对比
......@@ -144,7 +198,7 @@ echo "}"
```json
{
"check_type": "ntp_check",
"timestamp": "2026-05-13 15:00:00",
"timestamp": "2026-05-13 15:25:15",
"ntp_service": "chronyd",
"service_status": "running",
"time_sync_status": "synchronized",
......@@ -162,6 +216,7 @@ echo "}"
| 测试项 | 测试条件 | 预期结果 |
|--------|----------|----------|
| JSON格式 | 执行ntp_check.sh | 无双层引号 |
| JSON完整性 | 检查JSON结构 | 完整无截断 |
| JSON解析 | PowerShell解析JSON | 成功解析 |
| 值正确性 | 检查ntp_servers值 | 保持原始字符串 |
......@@ -172,15 +227,17 @@ echo "}"
3. 输入服务器连接信息
4. 观察NTP检测输出
5. 确认JSON格式正确
6. 确认ntp_servers值正确
6. 确认ntp_servers值完整
7. 确认JSON完整无截断
---
## 6. 部署说明
### 6.1 文件同步
- 主脚本:`check_server_health.ps1`
- Shell脚本:`lib/shell/ntp_check.sh`
- 目标位置:`C:\Users\UBAINS\Desktop\Test-module\lib\shell\`
- 目标位置:`C:\Users\UBAINS\Desktop\Test-module\`
### 6.2 依赖要求
- plink.exe(SSH连接工具)
......@@ -193,8 +250,10 @@ echo "}"
| 序号 | 优化内容 | 状态 |
|------|----------|------|
| 1 | 修复ntp_servers双层引号问题 | ✅ 已完成 |
| 2 | 验证JSON输出格式正确 | ✅ 已完成 |
| 3 | 确保ntp_servers值保持不变 | ✅ 已完成 |
| 2 | 修复JSON输出截断问题 | ✅ 已完成 |
| 3 | 使用临时文件避免截断 | ✅ 已完成 |
| 4 | 移除Shell脚本中的exec 2>/dev/null | ✅ 已完成 |
| 5 | 验证JSON输出格式正确 | ✅ 已完成 |
---
......@@ -207,17 +266,18 @@ echo "}"
- **不需要**使用转义字符 `\"`
- 直接传递变量或字符串即可
### 8.2 其他Shell脚本检查
### 8.2 问题二补充说明
#### 问题分析
JSON输出在 `"ntp_servers": "ntp1.aliyun.com,` 处被截断,这是因为plink.exe的输出缓冲区限制。
此问题可能存在于其他使用 `json_kv` 的脚本中,建议检查:
- `dns_check.sh`
- `middleware_check.sh`
- `resource_check.sh`
- `java_check.sh`
- `docker_check.sh`
- `config_check.sh`
#### 解决方案
通过将脚本输出先保存到远程临时文件,然后读取文件内容,避免了SSH输出缓冲区限制。
**检查要点**:搜索是否有 `\"` 这样的转义引号用法
#### 技术要点
- 使用 `> $outputFile 2>&1` 保存所有输出(包括stderr)
- 使用 `cat $outputFile` 读取文件内容
- 使用 `rm -f $outputFile` 清理临时文件
---
......
......@@ -24,6 +24,26 @@ Write-Log : 无法对参数“Level”执行参数验证。参数“DEBUG”不
```
### 1.2 问题二:JSON解析失败
```ignorelang
[2026-05-13 15:23:37] [INFO] ========== 开始资源检测 (Shell模式) ==========
[2026-05-13 15:23:38] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test-module\pscp.exe
[2026-05-13 15:23:38] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test-module\lib\shell\common.sh -> root@192.168.5.46:/tmp/health_check/
[2026-05-13 15:23:38] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test-module\pscp.exe
[2026-05-13 15:23:38] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test-module\lib\shell\resource_check.sh -> root@192.168.5.46:/tmp/health_check/
[2026-05-13 15:23:39] [ERROR] [SHELL] JSON解析失败: 无效的 JSON 基元: 已用。
[2026-05-13 15:23:39] [INFO] [SHELL] 原始输出前200字符: {
"check_type": "resource_check",
"timestamp": "2026-05-13 15:23:39",
"cpu": {
"cores": 8,
"usage_percent": 4.0,
"load_average": "0.61, 0.74, 0.75"
},
"memory": {
"total_mb":
[2026-05-13 15:23:39] [ERROR] [资源] Shell脚本执行失败
```
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
......
# _PRD_模块化拆分后资源检测脚本执行错误_问题处理 - 计划执行文档
> 创建时间:2026-05-13
> 更新时间:2026-05-13(补充问题二修复)
> 状态:已完成
> 来源:`Docs/PRD/服务自检/问题修复/_PRD_模块化拆分后资源检测脚本执行错误_问题处理.md`
......@@ -9,10 +10,11 @@
## 1. 问题分析
### 1.1 核心问题
资源检测Shell脚本执行时出现个错误:
资源检测Shell脚本执行时出现个错误:
1. **JSON解析失败**:输出包含中文"已用"等非JSON内容
2. **Write-Log参数错误**:使用了不存在的"DEBUG"日志级别
3. **JSON输出截断**:plink.exe输出被截断,导致JSON不完整
### 1.2 错误详情
......@@ -25,7 +27,7 @@ Write-Log : 无法对参数"Level"执行参数验证。参数"DEBUG"不属于 Va
- `Write-Log` 函数仅支持:INFO、WARN、ERROR、SUCCESS 四种级别
- 代码中使用了不存在的 `DEBUG` 级别
#### 问题二:JSON解析失败
#### 问题二:JSON解析失败(初步修复)
```
[SHELL] JSON解析失败: 无效的 JSON 基元: 已用。
```
......@@ -35,6 +37,25 @@ Write-Log : 无法对参数"Level"执行参数验证。参数"DEBUG"不属于 Va
- JSON解析函数未完全过滤非JSON内容
- 中文输出干扰JSON解析
#### 问题三:JSON输出被截断(新增)
```
{
"check_type": "resource_check",
"timestamp": "2026-05-13 15:23:39",
"cpu": {
"cores": 8,
"usage_percent": 4.0,
"load_average": "0.61, 0.74, 0.75"
},
"memory": {
"total_mb":
```
**原因**
- plink.exe输出被截断,JSON不完整
- SSH命令输出缓冲区限制
- `exec 2>/dev/null` 导致错误被隐藏
---
## 2. 解决方案
......@@ -63,18 +84,36 @@ Write-Log -Level "INFO" -Message "[SHELL] 原始输出前200字符: $($JsonStrin
- 添加中文输出过滤(已用、总用量、Mem:、Swap:、Cpu等)
- 限制调试输出长度,避免控制台溢出
### 2.3 Shell脚本添加stderr抑制
### 2.3 修复JSON输出截断问题
**文件**`lib/shell/*.sh`(所有检测脚本)
**位置**主函数调用前
**文件**`check_server_health.ps1`
**位置**`Invoke-RemoteShellCheck` 函数
**添加内容**
```bash
# 将所有stderr重定向到/dev/null,确保只输出JSON
exec 2>/dev/null
main
**修复方案**
- 将脚本输出先保存到临时文件,再读取
- 避免 SSH 输出缓冲区限制
- 移除 `exec 2>/dev/null` 避免隐藏错误
**修改后**
```powershell
# 执行脚本并将输出保存到临时文件(避免输出被截断)
$outputFile = "/tmp/health_check_output_$ScriptName.json"
$cmd = "cd $RemotePath && chmod +x common.sh $ScriptName && ./$ScriptName $Arguments > $outputFile 2>&1; cat $outputFile; rm -f $outputFile"
$result = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
```
### 2.4 移除Shell脚本中的exec 2>/dev/null
**文件**`lib/shell/*.sh`(所有检测脚本)
**原因**
- `exec 2>/dev/null` 会导致错误信息被隐藏
- 影响调试和问题定位
- 已在SSH命令中使用 `2>&1` 合并stderr
**修改**
移除所有脚本末尾的 `exec 2>/dev/null`
---
## 3. 代码修改详情
......@@ -100,10 +139,39 @@ catch {
}
```
### 3.2 所有Shell脚本
### 3.2 Invoke-RemoteShellCheck 函数(关键修复)
**修改内容**
在主函数调用前添加 `exec 2>/dev/null`
使用临时文件避免输出截断
**代码变更**
```powershell
# 执行脚本并将输出保存到临时文件(避免输出被截断)
$outputFile = "/tmp/health_check_output_$ScriptName.json"
$cmd = "cd $RemotePath && chmod +x common.sh $ScriptName && ./$ScriptName $Arguments > $outputFile 2>&1; cat $outputFile; rm -f $outputFile"
$result = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $cmd
# 清理临时文件
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command "rm -rf $RemotePath" | Out-Null
# 检查输出并返回结果
if ($result.Output) {
# 处理输出(可能是数组或字符串)
if ($result.Output -is [array]) {
return $result.Output -join "`n"
} else {
return $result.Output.ToString()
}
} else {
Write-Log -Level "WARN" -Message "[SHELL] 脚本未返回输出: $ScriptName (退出码: $($result.ExitCode))"
return $null
}
```
### 3.3 所有Shell脚本
**修改内容**
移除主函数调用前的 `exec 2>/dev/null`
**受影响文件**
- `lib/shell/resource_check.sh`
......@@ -114,7 +182,7 @@ catch {
- `lib/shell/ntp_check.sh`
- `lib/shell/config_check.sh`
**代码变更**
**修改前**
```bash
# 执行主函数
# 将所有stderr重定向到/dev/null,确保只输出JSON
......@@ -122,6 +190,12 @@ exec 2>/dev/null
main
```
**修改后**
```bash
# 执行主函数
main
```
---
## 4. 测试验证
......@@ -130,8 +204,9 @@ main
| 测试项 | 测试命令 | 预期结果 |
|--------|----------|----------|
| 资源检测 | 选择Shell模式 | 成功获取CPU/内存/磁盘数据 |
| 资源检测 | 选择Shell模式 | 成功获取完整CPU/内存/磁盘数据 |
| JSON解析 | 查看日志输出 | 无"已用"等中文干扰 |
| JSON完整性 | 检查JSON结构 | JSON完整,无截断 |
| 日志级别 | 查看调试输出 | 使用INFO级别正常输出 |
### 4.2 验证步骤
......@@ -140,8 +215,9 @@ main
2. 选择Shell模式
3. 输入服务器连接信息
4. 观察资源检测输出
5. 确认JSON解析成功
6. 确认日志输出正常
5. 确认JSON完整(包含memory部分)
6. 确认JSON解析成功
7. 确认日志输出正常
---
......@@ -165,8 +241,25 @@ main
| 1 | 修正Write-Log日志级别错误 | ✅ 已完成 |
| 2 | 添加中文输出过滤 | ✅ 已完成 |
| 3 | 限制调试输出长度 | ✅ 已完成 |
| 4 | Shell脚本添加stderr抑制 | ✅ 已完成 |
| 5 | 更新所有7个Shell脚本 | ✅ 已完成 |
| 4 | 修复JSON输出截断问题 | ✅ 已完成 |
| 5 | 使用临时文件避免截断 | ✅ 已完成 |
| 6 | 移除Shell脚本中的exec 2>/dev/null | ✅ 已完成 |
| 7 | 更新所有7个Shell脚本 | ✅ 已完成 |
---
## 7. 问题二补充说明
### 7.1 问题分析
JSON输出在 `"total_mb":` 处被截断,导致解析失败。这是因为plink.exe的输出缓冲区限制,长输出被截断。
### 7.2 解决方案
通过将脚本输出先保存到远程临时文件,然后读取文件内容,避免了SSH输出缓冲区限制。
### 7.3 技术要点
- 使用 `> $outputFile 2>&1` 保存所有输出(包括stderr)
- 使用 `cat $outputFile` 读取文件内容
- 使用 `rm -f $outputFile` 清理临时文件
---
......
......@@ -9,7 +9,7 @@
# ========================================
# 数据库列表(数组形式)
DATABASES=("offline" "nacos_mysql" "devops_voice" "huazhao2")
DATABASES=("offline" "nacos_mysql" "devops_voice" "huazhao2" "ubains" "devops")
# 备份路径配置
BACKUP_BASE="/data/bakup/mysql"
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论