2014-10-03 40 views
1

我遇到了这个很好的命令dmesg -w,它会在插入/移除新设备时输出设备信息。暂停bash脚本,直到“dmesg -w”输出任何东西

有没有办法使用此命令来暂停脚本,直到用户插入任何类型的USB或SSD卡?我想输出重定向和使用read莫名其妙的......

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

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

你用什么操作系统支持-D标志到dmesg? – 2014-10-03 23:43:54

+1

在Linux上,至少有更好的方法来触发设备插入和删除事件 - 您可以使用udev或与OS操作系统相同的操作,只在设备插入和删除时触发,而不需要持续监视。 – 2014-10-04 00:30:04

+0

@Nick Russo我正在使用ArchLinux。 @Charles Duffy我没有'udev',但是我有'udevadm'。 – 71GA 2014-10-04 01:10:35

回答

2

此脚本计算多少sd[[:lower:]]线是目前在dmesg队列。然后等待更多的线出现。当他们这样做时,它打印它们:

#!/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 
+0

哦谢谢你,这是一个不错的增量hehehe实施。 :d – 71GA 2014-10-04 01:13:10

2

udevadmmonitor模式将提供uevent秒的饲料,因为它们产生的:

​​

还有这里的几件事情值得注意的是:

  • stdbuf用于work aroundudevadmoutput buffering behavior
  • --line-buffered告诉grep输出每一行,而不是将它保存在缓冲区中。
  • BASH process substitution<())用于将udevadm的输出转换为/dev/fd/*符号链接,即grep可以作为文件打开并读取。如果使用流水线(udevadm | grep),即使在grep进程退出后,udevadm进程也可能最终挂起,这反过来会阻塞父进程。
  • 删除连续流的参数-m
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操作。

现在我们知道如何绑定和解除绑定我们的背景执行命令的文件描述符,我们可以执行while循环,将read和处理文本的每一行通过文件描述符3提供:

exec 3< <(tail -f -n 0 '/var/log/messages') 

local line 

while IFS='' read line 
do 
    : 
done <&3 

read命令将耐心地等待文本描述符3上出现的新文本行,并且while命令将循环直到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文件重定向的解决方案,请参阅Bash: Capture output of command run in background中记录的几个有用的备选方案。