我遇到了这个很好的命令dmesg -w
,它会在插入/删除新设备时输出设备信息。
有没有办法使用此命令暂停脚本,直到用户插入任何类型的USB或SSD卡?我正在考虑重定向输出并以某种方式使用read
......
我正常使用下面的两个命令从dmesg获取设备名称:
SSD_DMESG=$(dmesg | tail -n1 | grep -o 'sd[[:lower:]]')
SSD=/dev/$SSD_DMESG
答案 0 :(得分:2)
此脚本计算dmesg队列中当前有多少sd[[:lower:]]
行。然后它等待出现更多行。当他们这样做时,会打印出来:
#!/bin/sh
n=$(dmesg | grep 'sd[[:lower:]]' | wc -l)
while [ "$n" -eq "$(dmesg | grep 'sd[[:lower:]]' | wc -l)" ]
do
sleep 0.1s
done
sleep 0.1s
dmesg | grep 'sd[[:lower:]]' | tail -n+$n
wc -l
用于提供行数。 tail -n+$n
用于删除先前存在的行。最后一个sleep
的目的是让内核有时间完成设备的处理。
以上是冗长的。如果您只想要sd?
符号而没有其他信息,请尝试:
#!/bin/sh
n=$(dmesg | grep -o 'sd[[:lower:]]' | wc -l)
while [ "$n" -eq "$(dmesg | grep -o 'sd[[:lower:]]' | wc -l)" ]
do
sleep 0.1s
done
sleep 0.1s
dmesg | grep -o 'sd[[:lower:]]' | tail -n+$n | sort -u
答案 1 :(得分:2)
udevadm
monitor
模式会在生成uevent
时提供grep --line-buffered -o -m1 'sd[a-z] ' \
<(stdbuf -i0 -o0 udevadm monitor --kernel --subsystem-match=block)
个Feed:
stdbuf
这里有一些值得注意的事情:
udevadm
用于work around --line-buffered
&#39; s output buffering behavior。grep
告诉<()
输入每一行,而不是将其保留在缓冲区中。udevadm
)用于将/dev/fd/*
的输出转换为grep
符号链接udevadm | grep
可以作为文件打开并读取从。如果使用了管道(udevadm
),grep
进程可能会在-m
进程退出后结束,这反过来会阻止父进程。答案 2 :(得分:1)
我刚刚解决了同样的问题。我正在尝试监视dmesg
,以便我可以在连接时发现USB MIDI设备。
首先,我们不要使用dmesg -w
,因为这样做也会显示过去最近发生的事件。相反,让tail /var/log/messages
处于刷新模式,指定最初显示的0
行:
tail -f -n 0 '/var/log/messages'
现在我们知道要监视的命令,我们如何等待符合条件的新dmesg
条目,然后终止我们的轮询?幸运的是,bash
重定向可以轻松地将任务放入后台,然后访问其STDOUT
和STDIN
:
exec 3< <( tail -f -n 0 '/var/log/messages' )
在这里,我们已将tail
操作的输出重定向到文件描述符3
,一旦遇到我们的标准,我们可以按照以下方式取消设置:
exec 3>&-
请注意,取消设置文件描述符也会终止(通过SIGPIPE)绑定到它的命令,因此在这种情况下,我们不必担心清除tail
操作。
既然我们知道如何将我们的backgrounded命令绑定和取消绑定到文件描述符,我们就可以执行while
循环read
并处理通过文件描述符{{1}提供的每行文本}}:
3
exec 3< <( tail -f -n 0 '/var/log/messages' )
local line
while IFS='' read line
do
:
done <&3
命令将耐心地等待文本描述符read
上出现新的文本行,而while命令将循环,直到3
命令表明没有更多的行要阅读的文字。 read
仅在文件描述符read
关闭时才这样做,并且由于该描述符绑定到3
,它永远不会自动关闭其输出,tail -f
循环不会终止,因此我们必须手动打破循环。
现在我们可以添加一个以某种方式评估while
的语句,并在某些特定条件匹配时中断循环。在这里,我们可以使用$line
的成功状态来确定我们是否找到了我们正在寻找的内容,如果是,请执行适当的操作,包括打破循环然后关闭文件描述符grep -o
:
3
如果您希望以这种方式实现不使用exec 3< <( tail -f -n 0 '/var/log/messages' )
local line
while IFS='' read line
do
echo "${line}" | grep -o 'sd[[:lower:]]' && {
echo "YAY! ${line} matched."
break
}
done <&3
exec 3>&-
文件重定向的解决方案,请参阅Bash: Capture output of command run in background中记录的几个有用的替代方案。
答案 3 :(得分:0)
这是我的两分钱。使用timeout
,journalctl
,stdbuf
和grep
;因此:
if timeout $max_to stdbuf -oL -eL journalctl -b -f | grep -l --line-buffered "."; then
# grep found what you were looking for.
else
# TIMEOUT
fi
让我们从grep
开始。找到匹配项后,带有grep的-l选项将立即返回。 --line-buffered
消除了仅使用grep的缓冲问题。 '。'会匹配任何东西。
journalctl -b -f
告诉journalctl从引导时间开始打印消息,并继续输出消息直到终止。这意味着您不必担心种族状况,即您要查找的消息是在致电dmesg
之前发生的。
stdbuf
将消除journalctrl的缓冲问题。
现在,对于政变,如果紧随其后的命令在给定的秒数内没有终止,timeout
命令将终止所有操作;美丽!