USB 장치를 플러그인 할 때 쉘 스크립트를 실행하는 방법


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새 규칙을 적용하기 위해 장치 를 실행 하거나 연결 했습니까 ?
Gilles 'SO- 악마 그만해'

예, 규칙을 편집 할 때마다 그렇게합니다. 그에 따라 질문을 편집했습니다. 이것이 udev가 한동안 작동하는 방식이지만 실행 중 3.5.0-23-generic입니다.
Redsandro

답변:


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

을 사용하면 envudev에서 어떤 환경이 설정되었는지 확인할 수 있으며을 사용 file하면 파일 유형을 발견 할 수 있습니다.

장치의 구체적인 속성은 lsusb

lsusb

준다

...
버스 001 장치 016 : ID 152d : 2329 JMicron Technology Corp./JMicron USA Technology Corp. JM20329 SATA Bridge
...


1
이건 재미 있네! / log /에 쓸 수있는 권한이없는 것 같습니다. 그것은 않습니다 / tmp를 /에 쓰기. 이전 테스트 스크립트를 읽을 권한이 없었습니다.
Redsandro

@Redsandro 이것은 의도적 인 것이 아니라 테스트 목적으로 만 사용 된 것입니다. 어쨌든, 나는 그것이 기뻤다. ;-)
Olaf Dietsche

이 질문 을 확인하여 지식이 가치가 있는지 확인해 보시기 바랍니다 . :)
Redsandro

3
ACTION=="add",규칙 정의에 직접 추가 할 수도 있습니다 .
Avindra Goolcharan

4

이것은 귀하의 질문에 대한 것이 아니라 귀하가하는 일에 관한 것입니다. udev에서 백업 스크립트를 시작하면 다음 두 가지 주요 문제가 발생합니다.

  1. scrpit은 장치가 준비되기 전에 시작되어 마운트 될 수 있습니다. / dev 노드를 사용하여 마운트하려면 KERNEL == "sd *"조건을 유지해야합니다.
  2. 더 중요한 것은, scirpt를 실행하는 데 시간이 걸리는 경우 (백업 스크립트의 경우에 쉽게 해당됨) 시작된 직후 (약 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가 쉘이 아니며 리디렉션이 작동하지 않는다는 것을 잊지 마십시오. RUN은 다음과 같아야합니다.

RUN + = "/ bin / sh -c '/ bin / echo 연결됨 >> / tmp / IomegaUsbPipe'"


명명 된 파이프를 많이 사용합니다. tmp로 임의의 파일을 만들고 명명 된 파이프 대신 파일을 찾을 수도 있는지 궁금합니다. 맞습니까?
jamescampbell

1

https://askubuntu.com/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
페어 포인트. 답변에서 링크 된 내 "실제"스크립트는 목록을 사용합니다. 여기에 붙여 넣은이 미니멀리스트 버전에서 엉망이되어 실수로 문자열을 사용했습니다. 감사! 답변을 업데이트했습니다.
Denilson Sá Maia

-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루트로 실행되고 권한 상승 문제입니다. 일반 사용자가 편집 할 수있는 파일이 루트로 실행됩니다.
게르트 반 덴 버그
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.