批次部署或遷移伺服器時,需快速修改網卡 IP 設定。本文提供一支參數化 Shell 腳本,讀取 /etc/sysconfig/network-scripts/ifcfg-eth0 与 /etc/sysconfig/network 現有值,以 sed -i 就地替換為新 IP/Netmask/Gateway,並自動重啟網路服務生效。附帶參數檢查、備份原檔、錯誤碼回傳、systemd 相容版本,適合納入 Ansible、Kickstart、PXE 自動化流程。
一、腳本完整內容 (ip_change.sh)
#!/bin/bash
# 自動修改網卡 IP/Netmask/Gateway
# 用法:./ip_change.sh NEW_IP NEW_NETMASK NEW_GATEWAY [INTERFACE]
# 範例:./ip_change.sh 192.168.10.50 255.255.255.0 192.168.10.1 eth0
set -euo pipefail
# 參數解析
NEW_IP=${1:-}
NEW_NETMASK=${2:-}
NEW_GATEWAY=${3:-}
IFACE=${4:-eth0}
if [[ -z "$NEW_IP" || -z "$NEW_NETMASK" || -z "$NEW_GATEWAY" ]]; then
echo "Usage: $0 NEW_IP NEW_NETMASK NEW_GATEWAY [INTERFACE]"
echo "Example: $0 192.168.10.50 255.255.255.0 192.168.10.1 eth0"
exit 1
fi
# 配置檔路徑 (CentOS/RHEL 6/7)
IFCFG="/etc/sysconfig/network-scripts/ifcfg-$IFACE"
NETWORK="/etc/sysconfig/network"
# 檢查檔案存在
for f in "$IFCFG" "$NETWORK"; do
if [[ ! -f "$f" ]]; then
echo "ERROR: Config file not found: $f"
exit 2
fi
done
# 備份原檔 (含時間戳)
TS=$(date +%Y%m%d_%H%M%S)
cp "$IFCFG" "${IFCFG}.bak.$TS"
cp "$NETWORK" "${NETWORK}.bak.$TS"
echo "Backed up: ${IFCFG}.bak.$TS, ${NETWORK}.bak.$TS"
# 讀取舊值
OLD_IP=$(grep -i '^IPADDR=' "$IFCFG" | cut -d= -f2)
OLD_NETMASK=$(grep -i '^NETMASK=' "$IFCFG" | cut -d= -f2)
OLD_GATEWAY=$(grep -i '^GATEWAY=' "$NETWORK" | cut -d= -f2)
echo "Current: IP=$OLD_IP, NETMASK=$OLD_NETMASK, GATEWAY=$OLD_GATEWAY"
echo "New: IP=$NEW_IP, NETMASK=$NEW_NETMASK, GATEWAY=$NEW_GATEWAY"
# 就地替換 (sed -i)
sed -i "s/^IPADDR=.*/IPADDR=$NEW_IP/" "$IFCFG"
sed -i "s/^NETMASK=.*/NETMASK=$NEW_NETMASK/" "$IFCFG"
# GATEWAY 可能在 ifcfg 或 network 中,兩邊都替換以防萬一
sed -i "s/^GATEWAY=.*/GATEWAY=$NEW_GATEWAY/" "$IFCFG"
sed -i "s/^GATEWAY=.*/GATEWAY=$NEW_GATEWAY/" "$NETWORK"
# 驗證替換結果
echo "=== Updated $IFCFG ==="
grep -E '^(IPADDR|NETMASK|GATEWAY)=' "$IFCFG"
echo "=== Updated $NETWORK ==="
grep -E '^GATEWAY=' "$NETWORK"
# 重啟網路服務
echo "Restarting network..."
if command -v systemctl &>/dev/null && systemctl is-active --quiet NetworkManager; then
# NetworkManager 管理介面
nmcli con reload
nmcli con up "$IFACE"
else
# 傳統 network service
systemctl restart network 2>/dev/null || /etc/init.d/network restart
fi
# 等待介面啟動並驗證
sleep 3
CURRENT_IP=$(ip -4 addr show "$IFACE" | grep -oP 'inet \K[\d.]+')
if [[ "$CURRENT_IP" == "$NEW_IP" ]]; then
echo "SUCCESS: Interface $IFACE now has IP $CURRENT_IP"
exit 0
else
echo "WARNING: IP not updated yet (current: $CURRENT_IP). Check logs."
exit 3
fi
二、關鍵技術細節
| 技術點 | 說明 |
set -euo pipefail | 嚴格模式:變數未設定報錯、命令失敗即退出、管線失敗傳遞 |
sed -i | 就地編輯檔案,無需臨時檔重導向 |
grep -i '^KEY=' | 忽略大小寫匹配行首鍵值,避免註解行干擾 |
| 雙重替換 GATEWAY | CentOS 6 常放 network,CentOS 7 常放 ifcfg-eth0,兩邊都改最保險 |
| 備份機制 | 時間戳備份,支援快速回滾 cp .bak.$TS $ORIG |
| NetworkManager 相容 | 偵測 NM 狀態,改用 nmcli 重載連線設定 |
| 驗證機制 | ip -4 addr show 確認新 IP 實際生效,非僅配置檔寫入 |
三、進階擴充:支援多介面、靜態路由、DNS
# 多介面迴圈版本片段
for IFACE in eth0 eth1; do
# 為每張卡準備對應參數陣列
# IP_ARRAY=(192.168.10.50 10.0.0.5)
# ...
done
# 修改 DNS (resolve.conf 或 ifcfg 中 DNS1/DNS2)
sed -i "/^DNS1=/d;/^DNS2=/d" "$IFCFG"
echo "DNS1=8.8.8.8" >> "$IFCFG"
echo "DNS2=1.1.1.1" >> "$IFCFG"
# 新增靜態路由
echo "192.168.20.0/24 via 192.168.10.1 dev $IFACE" > "/etc/sysconfig/network-scripts/route-$IFACE"
四、systemd 服務化 (開機自動套用)
cat > /etc/systemd/system/ip-change@.service <<'EOF'
[Unit]
Description=Apply IP config for %i
Before=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/ip_change.sh 192.168.10.50 255.255.255.0 192.168.10.1 %i
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable ip-change@eth0
五、常見問題與排解
| 現象 | 原因 | 解決 |
| 重啟後 IP 未生效 | NetworkManager 覆蓋配置、介面名不符、IP 衝突 | 用 nmcli con show 確認連線名稱;檢查 ip a;關閉 NM 管理該介面 nmcli dev set eth0 managed no |
| sed 替換失敗 | 配置檔格式不標準 (縮排、大小寫、多行) | 用 grep -n 確認行號,改用 sed -i '5s/.*/IPADDR=.../' 指定行號 |
| SSH 斷線無法重連 | 修改的是當前連線介面 IP | 在 screen/tmux 中執行,或透過 Console/IPMI 操作 |
| Gateway 無法連通 | 新 Gateway 不在同網段、VLAN 標籤錯誤 | 確認 ip route、ping -c 3 $NEW_GATEWAY |