Bagaimana cara mengeksekusi shellscript ketika saya mencolokkan USB-device


28

Saya ingin menjalankan skrip ketika saya mencolokkan perangkat di mesin Linux saya. Misalnya, jalankan xinputdi mouse atau skrip cadangan pada drive tertentu.

Saya telah melihat banyak artikel tentang ini, paling baru di sini dan di sini . Tapi saya tidak bisa membuatnya bekerja.

Berikut adalah beberapa contoh sederhana yang mencoba untuk mendapatkan setidaknya semacam respons.

/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

Folder aturan diawasi oleh inotifydan harus segera aktif. Saya terus memasang kembali keyboard, mouse, tablet, memorystick, dan usb-drive, tetapi tidak ada apa-apa. Tidak ada file log yang disentuh.

Sekarang, apa cara paling sederhana untuk setidaknya tahu ada sesuatu yang berhasil? Lebih mudah bekerja dari sesuatu yang berfungsi daripada dari sesuatu yang tidak.


1
Tidakkah Anda bermaksud memposting di Unix & Linux ? Apa versi kernel Anda? Apakah Anda menjalankan udevadm triggeratau menyambungkan perangkat untuk menerapkan aturan baru?
Gilles 'SO- stop being evil'

Ya, saya melakukan itu setelah setiap pengeditan aturan untuk mencobanya. Saya mengedit pertanyaan sesuai. Inilah cara udev bekerja untuk sementara waktu sekarang, tetapi saya sedang berlari 3.5.0-23-generic.
Redsandro

Jawaban:


24

Jika Anda ingin menjalankan skrip pada perangkat tertentu, Anda dapat menggunakan vendor dan id produk

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

    ATTRS{idVendor}=="152d", ATTRS{idProduct}=="2329", RUN+="/tmp/test.sh"
  • di 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

Dengan env, Anda dapat melihat lingkungan apa yang ditetapkan dari udev dan dengan file, Anda akan menemukan jenis file.

Atribut konkret untuk perangkat Anda dapat ditemukan bersama lsusb

lsusb

memberi

...
Bus 001 Perangkat 016: ID 152d: 2329 JMicron Technology Corp / JMicron USA Technology Corp JM20329 Jembatan SATA
...


1
Ini menarik! Tampaknya tidak memiliki izin untuk menulis ke / log /. Ini tidak menulis ke / tmp /. Saya kira juga tidak punya izin untuk membaca skrip test sebelumnya.
Redsandro

@Redsandro Ini tidak disengaja, hanya untuk, yah, tujuan pengujian. Bagaimanapun, saya senang itu membantu. ;-)
Olaf Dietsche

Saya ingin mendorong Anda untuk juga memeriksa pertanyaan ini dan melihat apakah pengetahuan Anda dapat berharga di sana. :)
Redsandro

3
Anda juga dapat menambahkan ACTION=="add",langsung ke definisi aturan.
Avindra Goolcharan

4

Ini bukan langsung tentang pertanyaan Anda tetapi tentang apa yang Anda lakukan. Jika Anda memulai skrip cadangan dari udev, Anda akan menghadapi dua masalah utama:

  1. Scrpit Anda mungkin dimulai sebelum perangkat siap dan dapat dipasang, Anda harus menjaga kondisi KERNEL == "sd *" jika Anda ingin menggunakan / dev node untuk memasangnya
  2. Lebih penting lagi, jika skirpt Anda membutuhkan waktu untuk dieksekusi (yang dapat dengan mudah terjadi dengan skrip cadangan) skirpt Anda akan dibunuh segera setelah dimulai (sekitar 5 detik)
  3. Anda akan menghadapi banyak masalah izin pengguna yang rumit

Saran saya adalah membuat skrip di rumah pengguna Anda yang mendengarkan pipa bernama dan itu akan dimulai secara tidak sinkron seperti:

#!/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"

Catatan: Saya menggunakan auto-mount dengan kde jadi saya memeriksa folder yang akan muncul. Anda dapat melewatkan parameter / dev / sd * di fifo dari aturan udev dan memasangnya sendiri di skrip. Untuk menulis di fifo jangan lupa bahwa udev bukan shell dan pengalihan tidak berfungsi. RUN Anda harus seperti:

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


Sangat banyak menggunakan pipa bernama di sini. Saya bertanya-tanya Anda juga bisa membuat file sewenang-wenang di tmp dan mencarinya juga bukan pipa bernama, benar?
jamescampbell

1

Saya telah memposting solusi di /ubuntu//a/516336 dan saya juga menyalin-menempelkan solusi di sini.

Saya menulis skrip Python menggunakan pyudev yang saya biarkan berjalan di latar belakang. Script itu mendengarkan acara udev (dengan demikian, ini sangat efisien) dan menjalankan kode apa pun yang saya inginkan. Dalam kasus saya, ini menjalankan xinputperintah untuk mengatur perangkat saya ( tautan ke versi terbaru ).

Ini versi singkat dari skrip yang sama:

#!/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
Sepertinya skrip yang bagus, +1. Satu hal yang saya sarankan adalah menggunakan daftar alih-alih hanya satu string call(). Dengan begitu, jika perlu memberikan argumen pada foobar.shskrip, Anda dapat melakukannya secara dinamis.
Sergiy Kolodyazhnyy

1
Titik adil. Skrip "asli" saya (ditautkan dari jawaban) menggunakan daftar. Dalam versi minimalis yang saya tempelkan di sini, saya mengacau dan secara tidak sengaja menggunakan string. Terima kasih! Saya sudah memperbarui jawabannya.
Denilson Sá Maia

-1

Untuk menjalankan skrip pada saat boot ketika perangkat usb dimasukkan, saya menggunakan solusi di bawah ini:

Format flashdisk atau penyimpanan usb lainnya dan berikan nama saat melakukannya. Kemudian /etc/rc.local tambahkan barisls -q /dev/disk/by-label > /home/pi/label.txt

itu akan membuat file txt bernama label.txt (bisa berupa nama lain)

sekali lagi di /etc/rc.local tambahkan 2 baris lagi:

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

Sekarang setiap flashdisk dengan nama USB_drive_name dimasukkan, itu akan menjalankan skrip.

Dengan sedikit modifikasi, solusi di atas dapat digunakan ketika sistem aktif dan berjalan.


Tidak menjawab pertanyaan: Ini hanya mencakup waktu boot (dan menggunakan udevuntuk waktu lain bukanlah "sedikit modifikasi") dan Raspberry Pi. Ada yang tidak perlu sudo- rc.localberjalan sebagai root, itu adalah masalah eskalasi hak istimewa - file yang dapat diedit oleh pengguna normal dijalankan sebagai root.
Gert van den Berg
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.