拔掉网络时退出脚本

拔掉网络时退出脚本

我正在尝试使用 Raspberry Pi 通过 eth0 记录来自传感器的数据。当我运行我的代码(以及 sigterms、kills、exit 等大约 100 个变体)时,集合在拔掉插头后不会消失,并且我的文件不会刷新。这是我的(大部分)代码的当前迭代。

blink是一个我已排除的函数,但它可以工作并且不能以编程方式交互。

有谁知道如何成功地使用断开网络电缆作为信号来刷新文件并终止我的脚本?

#!/bin/bash

# Function to check if the Ethernet interface is active
eth_active() {
    if ip link show eth0 up >/dev/null 2>&1; then
        return 0
    else
        return 1
    fi
}


dt=$(date '+%Y_%m_%d_%H_%M')
umask 0111
touch $dt.pcap

sleep 5

# Main script
if eth_active; then
# Ethernet active, execute the command
    dumpcap -i eth0 -P -w $dt.pcap &
    pid=$!
    if eth_active; then
        echo "working"
        sleep 2
    else
        kill -9 $pid
        echo "Ethernet interface is severed. Exiting..."
        blink
        shutdown -h now
    fi
else
# Ethernet interface is severed, exit the script
    echo "Not getting data"
    blink
    exit 0
fi

答案1

有谁知道我如何成功地使用拔出插头作为信号来刷新文件并终止我的脚本?

首先,该函数eth_active无法正确识别接口链路是否已连接。运行一点代码可以测试这一点:

iface=enxb827eb315364    # Interface name
while sleep 3; do date; ip link show "$iface" up; echo SS=$?; echo; done

退出状态显示为SS=…,您将看到它始终返回 0(“ok”),无论以太网连接如何:

Tue 10 Oct 09:52:41 BST 2023
2: enxb827eb315364: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether b8:27:eb:31:53:64 brd ff:ff:ff:ff:ff:ff
SS=0

Tue 10 Oct 09:52:44 BST 2023
2: enxb827eb315364: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000
    link/ether b8:27:eb:31:53:64 brd ff:ff:ff:ff:ff:ff
SS=0

[…]

Tue 10 Oct 09:52:53 BST 2023
2: enxb827eb315364: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether b8:27:eb:31:53:64 brd ff:ff:ff:ff:ff:ff
SS=0

那么让我们解决这个问题:

# Check if the Ethernet interface is active.
# Usage: eth_active [<interface_name>]
# Omitting the <interface_name> will default to eth0
#
eth_active() {
    ip link show "${1:-eth0}" up 2>&1 | grep -qF "state UP"
}

函数的返回值可以从状态中得出grep(0=文本匹配成功),因此不需要if … then返回显式值。

接下来,您需要一个循环来检查这一点,否则程序将简单地从上到下运行,开始dumpcap作为子进程启动,然后退出。

我不明白您试图在问题描述中体现的逻辑,因此我在这里进行了简化以说明您如何编写循环。它并不是为了替换您的代码,而是为了帮助您了解如何自己编写代码:

# Set the interface name
iface=eth0

# Start the packet capture
dumpcap -i "$iface" -P -w "$(date +'%Y-%m-%d_%H%M').pcap" &
pid=$!  

# Do nothing until either the network cable is pulled or dumpcap dies
while eth_active "$iface" && kill -0 "$pid" 2>/dev/null
do
    sleep 3
done

# Kill dumpcap if it's still around
kill "$pid" 2>/dev/null && ( sleep 3; kill -KILL "$pid" 2>/dev/null ) &

请注意,我们最初并没有使用kill -9( SIGKILL) ,而是使用默认的SIGTERM。通常SIGKILL这是一个糟糕的选择,因为它不允许目标进程有任何清理的机会;将其视为一个大坏锤,而不是终止进程的常规方法。在dumpcap这种情况下,它SIGTERM会告诉它退出 - 更重要的是,将任何未完成的输出刷新到捕获文件中。然而,为了防止它发生扭曲,我们等待三秒钟,然后用大锤子敲击它。如果它已经消失了,那么我们只会收到一个错误kill,但这在这里不是问题。

答案2

你可以尝试这样的事情(未经测试):

if eth_active; then
    # Ethernet active, execute the command
    dumpcap -i eth0 -P -w "$dt.pcap" &
    pid=$!

else
    # Ethernet interface is severed, exit the script
    echo "Not getting data"
    blink
    exit 0
fi

## run until eth_active is false
while eth_active; do
    echo "working"
    sleep 2
done

## Only kill the PID if the $pid variable is not empty
[ -n "$pid" ] && kill -9 "$pid"

echo "Ethernet interface is severed. Exiting..."
blink
shutdown -h now

这将测试接口是否已启动,如果是,将启动您的命令,然后每 2 秒再次测试一次接口,并继续执行脚本的其余部分,如果接口已关闭,则关闭计算机。

但是,我不太明白你想要的逻辑。如果运行这个脚本时接口没有启动,它会直接关闭机器,这是你想要的吗?


重要的: 看克里斯·戴维斯的回答这表明您的eth_active()工作没有按您的预期进行。

相关内容