You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell脚本中free命令执行异常,无法写入目标文件求助

问题:Bash脚本查询多服务器资源信息时free命令异常

脚本原代码

USER=name
DEST=\result.txt
FILE=\servers.txt

GetTotalCores="nproc --all"
GetMemoryDetails=" df -h | awk 'NR==2{print \$2}'"
GetMemoryDetails2=" df -h | awk 'NR==2{print \$2}'"
GetDetails="free -h"

for i in `cat $FILE`; 
do
    echo -n "."q
    D= "$(ssh name@$i.com $GetDetails)"
    A="$(ssh  name@$i.com $GetTotalCores)"
    B="$(ssh  name@$i.com $GetMemoryDetails)"
    C="$(ssh  name@$i.com $GetMemoryDetails2)"
    
    echo "${i} CPU: ${A} MEMORY: ${B}  ${C} RAM: ${D} >" >> ${DEST}

done
exit 0

报错信息

script.sh: line 27:               total        used        free      shared  buff/cache   available
Mem:       24669784     9181092      229024     1432604    15259668    13685616
Swap:       4063228      501760     3561468: No such file or directory

问题分析与修复

1. 变量赋值的空格错误

最核心的问题是D= "$(ssh name@$i.com $GetDetails)"这一行:Bash变量赋值时,等号前后不能有空格。你这里等号后加了空格,Bash会把"$(ssh ...)"的输出当成要执行的命令,而不是赋值给D,这就导致free -h的输出被当作命令行指令执行,从而报出“找不到文件或目录”的错误。

2. 多余的转义符与无效字符

  • DEST=\result.txt和FILE=\servers.txt里的反斜杠是多余的,直接写DEST=result.txt即可;
  • echo -n "."q里的q是无效字符,应该改成echo -n "."用于进度提示;
  • 最后echo语句里的>是多余的,会被Bash当作重定向符号处理,导致输出异常。

3. SSH命令的引号问题

当执行带管道或空格的远程命令时,需要用双引号包裹命令变量,避免本地Shell解析管道。比如ssh name@$i.com "$GetMemoryDetails",否则管道会在本地执行,而不是远程服务器。

4. 冗余的SSH连接

原脚本对同一服务器多次发起SSH连接,既低效又容易出问题,可以合并为一次SSH调用获取所有信息,减少连接开销。

修复后的脚本

USER=name
DEST=result.txt
FILE=servers.txt

# 定义远程执行的命令,注意awk里的$要转义,因为是在本地字符串中
GetTotalCores="nproc --all"
GetDiskUsage="df -h | awk 'NR==2{print \$2}'"
GetMemDetails="free -h"

for i in $(cat "$FILE"); do
    echo -n "."
    # 一次SSH连接获取所有需要的信息,用分隔符区分结果
    remote_output=$(ssh "$USER@$i.com" "$GetTotalCores; $GetDiskUsage; $GetMemDetails")
    # 按换行分割结果,分别赋值
    read -r A B <<< "$(echo "$remote_output" | head -2)"
    D=$(echo "$remote_output" | tail -3)
    
    echo "${i} CPU: ${A} DISK: ${B} RAM: ${D}" >> "$DEST"
done
echo -e "\nDone, results saved to $DEST"
exit 0

额外说明

  • 原脚本中GetMemoryDetails和GetMemoryDetails2完全重复,且实际是查询磁盘(df命令),所以修复时改成了GetDiskUsage更贴合实际用途;
  • 使用$(cat "$FILE")代替反引号,是更现代的Bash写法,可读性更强;
  • 用一次SSH连接获取所有数据,大幅提升脚本执行效率,尤其是服务器数量较多时。

内容的提问来源于stack exchange,提问作者S8Z

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:55:35