插入USB设备时如何执行ShellScript


28

当我在Linux机器中插入设备时,我想执行脚本。例如,xinput在鼠标或特定驱动器上的备份脚本上运行。

我已经在这里这里看到了很多有关此的文章。但是我就是无法正常工作。

这是一些简单的示例,试图至少获得某种响应。

/etc/udev/rules.d/test.rules

#KERNEL=="sd*", ATTRS{vendor}=="*", ATTRS{model}=="*", ATTRS{serial}=="*", RUN+="/usr/local/bin/test.sh"
#KERNEL=="sd*", ACTION=="add", "SUBSYSTEM=="usb", ATTRS{model}=="My Book 1140    ", ATTRS{serial}=="0841752394756103457194857249", RUN+="/usr/local/bin/test.sh"
#ACTION=="add", "SUBSYSTEM=="usb", RUN+="/usr/local/bin/test.sh"
#KERNEL=="sd*", ACTION=={add}, RUN+="/usr/local/bin/test.sh"
KERNEL=="sd*", RUN+="/usr/local/bin/test.sh"
KERNEL=="*", RUN+="/usr/local/bin/test.sh"

/usr/local/bin/test.sh

#!/usr/bin/env bash
echo touched >> /var/log/test.log

if [ "${ACTION}" = "add" ] && [ -f "${DEVICE}" ]
then
    echo ${DEVICE} >> /var/log/test.log
fi

规则文件夹受到监视,inotify并且应立即处于活动状态。我一直在重新插入键盘,鼠标,平板电脑,记忆棒和USB驱动器,但一无所获。没有触摸日志文件。

现在,至少知道某事正在工作的最简单方法是什么?从有效的工作上进行工作比在无效的工作上进行工作容易。


1
您不是要在Unix和Linux上发布吗?您的内核版本是什么?您是否运行udevadm trigger或插入设备以应用新规则?
吉尔斯(Gillles)“所以别再作恶了”

是的,我会在每次修改规则后进行尝试。我相应地编辑了问题。这是udev暂时工作的方式,但是我正在运行3.5.0-23-generic
Redsandro

Answers:


24

如果要在特定设备上运行脚本,则可以使用供应商和产品ID

  • /etc/udev/rules.d/test.rules

    ATTRS{idVendor}=="152d", ATTRS{idProduct}=="2329", RUN+="/tmp/test.sh"
  • test.sh

    #! /bin/sh
    
    env >>/tmp/test.log
    file "/sys${DEVPATH}" >>/tmp/test.log
    
    if [ "${ACTION}" = add -a -d "/sys${DEVPATH}" ]; then
    echo "add ${DEVPATH}" >>/tmp/test.log
    fi
    

使用env,您可以看到从udev设置的环境,使用file,您将发现文件类型。

您设备的具体属性可以通过以下方式发现 lsusb

lsusb

...
总线001设备016:ID 152D:2329智微科技公司/ JMicron的美国科技公司JM20329 SATA桥
...


1
这是有趣的!似乎它没有写/ log /的权限。它确实写入/ tmp /。我想它也没有阅读我以前的测试稿的许可。
Redsandro

@Redsandro这不是故意的,只是出于测试目的。无论如何,我很高兴它有所帮助。;-)
Olaf Dietsche

我想鼓励您也研究这个问题,看看您的知识是否对您有价值。:)
Redsandro

3
您也可以ACTION=="add",直接添加到规则定义。
Avindra Goolcharan '16

4

这不直接与您的问题有关,而与您在做什么有关。如果从udev启动备份脚本,将面临两个主要问题:

  1. 您的scrpit可能在设备准备就绪并可以挂载之前启动,如果要使用/ dev节点挂载它,则必须保持KERNEL ==“ sd *”条件
  2. 更重要的是,如果脚本执行需要一些时间(使用备份脚本很容易发生这种情况),它将在启动后不久(约5秒)被杀死。
  3. 您将面临许多复杂的用户权限问题

我的建议是在用户主目录中创建一个脚本,该脚本侦听命名管道,并且该脚本将以异步方式启动,例如:

#!/bin/bash

PIPE="/tmp/IomegaUsbPipe"
REMOTE_PATH="/path/to/mount/point"
LOCAL_PATH="/local/path/"


doSynchronization()
{
  #your backup here
}

trap "rm -f $PIPE" EXIT

#If the pipe doesn't exists, create it
if [[ ! -p $PIPE ]]; then
    mkfifo $PIPE
fi

#If the disk is already plugged on startup, do a syn
if [[ -e "$REMOTE_PATH" ]]
then
    doSynchronization
fi

#Make the permanent loop to watch the usb connection
while true
do
    if read line <$PIPE; then
        #Test the message red from the fifo
        if [[ "$line" == "connected" ]]
        then
            #The usb has been plugged, wait for disk to be mounted by KDE
            while [[ ! -e "$REMOTE_PATH" ]]
            do
                sleep 1
            done
            doSynchronization
        else
            echo "Unhandled message frome fifo : [$line]"
        fi
    fi
done
echo "Reader exiting"

注意:我在kde中使用了自动挂载,因此我检查了该文件夹是否出现。您可以通过udev规则在fifo中传递/ dev / sd *参数,并将其自己安装在脚本中。在fifo中编写时,请不要忘记udev不是shell,并且重定向不起作用。您的RUN应该像:

RUN + =“ / bin / sh -c'/ bin / echo已连接>> / tmp / IomegaUsbPipe'”


在这里大量使用命名管道。我想知道您是否还可以在tmp中创建一个任意文件,并查找它而不是命名管道,对吗?
jamescampbell '18 -10-27

1

我已经在/ubuntu//a/516336上发布了一个解决方案,并且我还在这里复制粘贴该解决方案。

我使用pyudev编写了Python脚本,但仍在后台运行。该脚本侦听udev事件(因此非常有效),并运行我想要的任何代码。就我而言,它运行xinput命令来设置我的设备链接到最新版本)。

这是同一脚本的简短版本:

#!/usr/bin/env python3

import pyudev
import subprocess

def main():
    context = pyudev.Context()
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by(subsystem='usb')
    monitor.start()

    for device in iter(monitor.poll, None):
        # I can add more logic here, to run different scripts for different devices.
        subprocess.call(['/home/foo/foobar.sh', '--foo', '--bar'])

if __name__ == '__main__':
    main()

1
看起来像个不错的脚本,+ 1。我建议的一件事是使用list而不是中的一个字符串call()。这样,如果有必要向foobar.sh脚本提供参数,则可以动态地执行此操作。
Sergiy Kolodyazhnyy

1
有道理。我的“真实”脚本(从答案链接)使用一个列表。在此粘贴的这个极简版本中,我搞砸了,不小心使用了字符串。谢谢!我已经更新了答案。
丹尼尔森·萨玛

-1

要在插入USB设备时在启动时运行脚本,请使用以下解决方案:

格式化pendrive或任何其他USB存储器,并在命名时给它命名。然后在/etc/rc.local 添加行ls -q /dev/disk/by-label > /home/pi/label.txt

它将创建一个名为label.txt的txt文件(可以是任何其他名称)

然后再次在/etc/rc.local中添加另外两行:

if  grep -q USB_drive_name /home/pi/label.txt; then
sudo /home/pi/script.sh

现在,每次插入名称为USB_drive_name的Pendrive时,它将运行脚本。

稍作修改,上面的解决方案就可以在系统启动和运行时使用。


没有回答这个问题:它仅涵盖启动时间(并且udev用于其他时间并不是“很少的修改”)和Raspberry Pi。没有必要sudo- rc.local以root身份运行,这是特权提升问题-普通用户可以编辑的文件以root身份运行。
Gert van den Berg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.