我正在尝试使用 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()
工作没有按您的预期进行。