web-dev-qa-db-ja.com

USBデバイスをプラグインしたときにシェルスクリプトを実行する方法

Linuxマシンにデバイスを接続したときにスクリプトを実行したい。たとえば、マウスでxinputを実行するか、特定のドライブでbackupscriptを実行します。

私はこれについて多くの記事を見てきましたが、最近は here および here です。しかし、私はそれを機能させることができません。

以下は、少なくともある種の応答を得ようとするいくつかの簡単な例です。

/ 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

Rulesフォルダーはinotifyによって監視され、すぐにアクティブになります。キーボード、マウス、タブレット、メモリスティック、USBドライブを何度も接続し直しますが、何もしません。変更されたログファイルはありません。

さて、少なくとも何かが機能していることを知るための最も簡単な方法は何でしょうか?機能していないものから作業するよりも、機能しているものから作業する方が簡単です。

31
Redsandro

特定のデバイスでスクリプトを実行する場合は、ベンダーIDと製品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 Technology Corp./JMicron USA Technology Corp. JM20329 SATA Bridge
...

24
Olaf Dietsche

これは直接あなたの質問についてではなく、あなたが何をしているのかについてです。 udevからバックアップスクリプトを開始すると、2つの主要な問題に直面します。

  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で自動マウントを使用しているため、フォルダーが表示されるかどうかを確認します。/dev/sd *パラメータをufoルールからfifoに渡して、スクリプトに自分でマウントできます。 fifoで書くには、udevがシェルではなく、そのリダイレクトが機能しないことを忘れないでください。あなたのRUNは次のようになります:

RUN + = "/ bin/sh -c '/ bin/echo connected >>/tmp/IomegaUsbPipe'"

4
Olivier Laporte

https://askubuntu.com/a/516336 に解決策を投稿しました。また、ここに解決策をコピーして貼り付けています。

Pythonスクリプトを使用して pyudev を使用して、バックグラウンドで実行したままにします。このスクリプトは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

USBデバイスが挿入されているときに起動時にスクリプトを実行するには、以下のソリューションを使用します。

ペンドライブまたはその他のUSBストレージをフォーマットし、その際に名前を付けます。次に/etc/rc.local行を追加ls -q /dev/disk/by-label > /home/pi/label.txt

label.txtという名前のtxtファイルを作成します(他の名前でもかまいません)

次に/etc/rc.localに別の2行を追加します。

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

これで、名前がUSB_drive_nameのペンドライブが挿入されるたびに、スクリプトが実行されます。

上記のいくつかの小さな変更により、システムが稼働しているときにソリューションを使用できます。

0