暂停bash脚本,直到“dmesg -w”输出任何内容

时间:2014-10-03 23:39:58

标签: bash

我遇到了这个很好的命令dmesg -w,它会在插入/删除新设备时输出设备信息。

有没有办法使用此命令暂停脚本,直到用户插入任何类型的USB或SSD卡?我正在考虑重定向输出并以某种方式使用read ......

我正常使用下面的两个命令从dmesg获取设备名称:

SSD_DMESG=$(dmesg | tail -n1 | grep -o 'sd[[:lower:]]')
SSD=/dev/$SSD_DMESG

4 个答案:

答案 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告诉<()输入每一行,而不是将其保留在缓冲区中。
  • BASH process substitutionudevadm)用于将/dev/fd/*的输出转换为grep符号链接udevadm | grep可以作为文件打开并读取从。如果使用了管道(udevadm),grep进程可能会在-m进程退出后结束,这反过来会阻止父进程。
  • 删除连续流的{{1}}参数。

答案 2 :(得分:1)

我刚刚解决了同样的问题。我正在尝试监视dmesg,以便我可以在连接时发现USB MIDI设备。

首先,我们不要使用dmesg -w,因为这样做也会显示过去最近发生的事件。相反,让tail /var/log/messages处于刷新模式,指定最初显示的0行:

tail -f -n 0 '/var/log/messages'

现在我们知道要监视的命令,我们如何等待符合条件的新dmesg条目,然后终止我们的轮询?幸运的是,bash重定向可以轻松地将任务放入后台,然后访问其STDOUTSTDIN

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)

这是我的两分钱。使用timeoutjournalctlstdbufgrep;因此:

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命令将终止所有操作;美丽!