วิธีดำเนินการ shellscript เมื่อฉันเสียบอุปกรณ์ USB


28

ฉันต้องการรันสคริปต์เมื่อฉันเสียบอุปกรณ์ในเครื่อง Linux ของฉัน ตัวอย่างเช่นรันxinputบนเมาส์หรือ backupscript บนไดรฟ์บางตัว

ฉันได้เห็นบทความจำนวนมากเกี่ยวกับเรื่องนี้ส่วนใหญ่เมื่อเร็ว ๆ นี้ที่นี่และที่นี่ แต่ฉันไม่สามารถทำงานได้

ต่อไปนี้เป็นตัวอย่างง่ายๆที่พยายามรับการตอบกลับอย่างน้อย

/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 'ดังนั้นหยุดความชั่วร้าย'

ใช่ฉันทำทุกครั้งหลังจากแก้ไขกฎเพื่อลองใช้ ฉันแก้ไขคำถามตามนั้น นี่เป็นวิธีที่ evev ทำงานได้พักหนึ่งแล้ว แต่ฉันกำลังวิ่ง3.5.0-23-genericอยู่
Redsandro

คำตอบ:


24

หากคุณต้องการเรียกใช้สคริปต์บนอุปกรณ์เฉพาะคุณสามารถใช้รหัสผู้ขายและผลิตภัณฑ์

  • ใน /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 Bus 016: ID 152d: 2329 JMicron Technology Corp. / JMicron USA Technology Corp. JM20329 สะพาน SATA
...


1
สิ่งนี้น่าสนใจมาก! ดูเหมือนว่ามันไม่ได้รับอนุญาตให้เขียนไปยัง / log / มันไม่เขียนไป tmp / / ฉันเดาว่ามันไม่ได้รับอนุญาตให้อ่าน testcript ก่อนหน้าของฉัน
Redsandro

@Redandro นี่ไม่ใช่เจตนาสำหรับวัตถุประสงค์ในการทดสอบเท่านั้น อย่างไรก็ตามฉันดีใจที่มันช่วย ;-)
Olaf Dietsche

ฉันต้องการสนับสนุนให้คุณลองดูคำถามนี้และดูว่าความรู้ของคุณมีค่าหรือไม่ :)
Redsandro

3
คุณยังสามารถเพิ่มลงACTION=="add",ในคำจำกัดความของกฎได้โดยตรง
Avindra Goolcharan

4

นี่ไม่ใช่คำถามของคุณโดยตรง แต่เกี่ยวกับสิ่งที่คุณทำ หากคุณเริ่มต้นสคริปต์สำรองจาก udev คุณจะพบกับปัญหาหลักสองประการ:

  1. scrpit ของคุณอาจเริ่มต้นก่อนที่อุปกรณ์จะพร้อมและสามารถติดตั้งได้คุณจะต้องรักษา KERNEL == "sd *" หากคุณต้องการใช้โหนด / dev เพื่อติดตั้ง
  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 ดังนั้นฉันจึงตรวจสอบว่าโฟลเดอร์ปรากฏขึ้นหรือไม่ คุณสามารถส่งผ่านพารามิเตอร์ / dev / sd * ใน fifo จากกฎ udev และติดมันด้วยตัวคุณเองในสคริปต์ หากต้องการเขียนใน Fifo อย่าลืมว่า udev ไม่ใช่เชลล์และการเปลี่ยนเส้นทางนั้นไม่ทำงาน RUN ของคุณควรเป็นเช่น:

RUN + = "/ bin / sh -c '/ bin / echo เชื่อมต่อ >> / tmp / IomegaUsbPipe'"


ใช้ท่อที่มีชื่ออย่างดีเยี่ยมที่นี่ ฉันสงสัยว่าคุณสามารถสร้างไฟล์ตามอำเภอใจใน tmp และค้นหาไฟล์นี้แทนที่จะใช้ไพพ์ที่มีชื่อใช่ไหม
jamescampbell

1

ฉันโพสต์วิธีแก้ปัญหาใน/ubuntu//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
ดูเหมือนสคริปต์ที่ดี +1 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

มันจะสร้างไฟล์ txt ชื่อ label.txt (สามารถเป็นชื่ออื่นได้)

จากนั้นอีกครั้งใน /etc/rc.local เพิ่มอีก 2 บรรทัด:

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

ตอนนี้ทุกครั้งที่ใส่ pendrive ด้วยชื่อ USB_drive_name มันจะเรียกใช้สคริปต์

ด้วยการปรับเปลี่ยนเล็กน้อยด้านบนโซลูชันสามารถใช้งานได้เมื่อระบบเริ่มทำงาน


ไม่ตอบคำถาม: สิ่งนี้ครอบคลุมเฉพาะเวลาบูตเท่านั้น (และการใช้udevในบางครั้งไม่ใช่ "การปรับเปลี่ยนเล็กน้อย") และ Raspberry Pi มีความจำเป็นsudo- rc.localทำงานตามรูทเป็นปัญหาการยกระดับสิทธิ์ - ไฟล์ที่แก้ไขได้โดยผู้ใช้ปกติจะถูกเรียกใช้เป็นรูท
Gert van den Berg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.