Bir USB aygıtını taktığımda bir kabuk komut dosyası yürütme


28

Linux makinemde bir cihaz taktığımda bir komut dosyası çalıştırmak istiyorum. Örneğin, xinputfareyle veya belirli bir sürücüde bir yedekleme komut dosyasını çalıştırın.

Bu konuda pek çok yazı gördüm, en son burada ve burada . Ama çalışmasını sağlayamıyorum.

İşte en azından bir tür yanıt almaya çalışırken bazı basit örnekler.

/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

Kurallar klasörü tarafından izlenir inotifyve hemen aktif olmalıdır. Klavyemi, fareyi, tabletimi, memorystick'i ve usb sürücümü değiştirmeye devam ediyorum ama hiçbir şey. Hiçbir günlük dosyasına dokunulmadı.

Şimdi, en azından bir şeyin işe yaradığını bilmenin en basit yolu ne olurdu? Çalışmakta olan bir şeyle çalışmak, olmayan bir şeyden daha kolaydır.


1
Unix ve Linux'ta yayın yapmak istemedin mi? Çekirdek versiyonun nedir? udevadm triggerYeni kuralı uygulamak için bir cihazı çalıştırdınız veya taktınız mı?
Gilles 'SO- kötülük yapmayı bırak'

Evet, bunu denemek için her kural düzenlemesinden sonra yapıyorum. Soruyu buna göre düzenledim. Uudev bir süredir bu şekilde çalışıyor, ama ben koşuyorum 3.5.0-23-generic.
Redsandro,

Yanıtlar:


24

Komut dosyasını belirli bir cihazda çalıştırmak istiyorsanız, satıcıyı ve ürün kimliklerini kullanabilirsiniz.

  • İçinde /etc/udev/rules.d/test.rules:

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

İle envhangi ortamın kurulduğunu görebilirsiniz ve ile filedosya türünü keşfedersiniz.

Cihazınız için somut özellikler ile keşfedilebilir lsusb

lsusb

verir

...
Otobüs 001 Cihaz 016: ID 152d: 2329 JMicron Teknoloji Şirketi / JMicron USA Teknoloji Şirketi JM20329 SATA Köprüsü
...


1
Bu ilginç! / Log / 'a yazma izninin olmadığı görülüyor. Bu does / tmp / yazı göndermekte. Sanırım önceki test senaryolarımı da okuma iznim yoktu.
Redsandro

@Redsandro Bu kasıtlı değildi, sadece test amaçlı kullanıldı. Neyse, yardım ettiğine sevindim. ;-)
Olaf Dietsche 16: 24'de

Sizi de bu soruyu incelemenizi ve bilginizin orada değerli olup olmadığına bakın. :)
Redsandro

3
Ayrıca ACTION=="add",doğrudan kural tanımına ekleyebilirsiniz .
Avindra Goolcharan

4

Bu doğrudan sorunuzla değil ne yaptığınızla ilgilidir. Eğer udev'den bir yedekleme betiği başlatırsanız iki ana sorunla karşılaşacaksınız:

  1. Scrpit'iniz cihaz hazır olmadan ve monte edilmeden önce başlatılmış olabilir, / dev düğümünü monte etmek istiyorsanız kullanmak için KERNEL == "sd *" koşulunu korumanız gerekir.
  2. Daha da önemlisi, eğer scirpt'inizin yürütülmesi biraz zaman alırsa (ki bu bir yedekleme betiği ile oldukça zor olabilir) başladıktan kısa bir süre sonra öldürülecek (yaklaşık 5s)
  3. Birçok karmaşık kullanıcı izni sorunuyla karşılaşacaksınız

Benim tavsiyem, kullanıcı evinizde adlandırılmış bir boruyu dinleyen ve eşzamanlı olmayan şekilde başlatılacak olan bir komut dosyası oluşturmaktır:

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

Not: kde ile otomatik montaj kullanıyorum, böylece klasörün görünüp görünmediğini kontrol ediyorum. / Dev / sd * parametresini udev kuralından fifo'da geçirebilir ve kendiniz komut dosyasına ekleyebilirsiniz. Beşe yazmak, udev'in bir kabuk olmadığını ve yönlendirme işleminin işe yaramadığını unutmayın. RUN'unuz aşağıdaki gibi olmalıdır:

RUN + = "/ bin / sh -c '/ bin / eko bağlı >> / tmp / IomegaUsbPipe'"


Burada adlandırılmış boruların harika kullanımı. Ayrıca, tmp'de rastgele bir dosya oluşturabilir ve adlandırılmış bir boru yerine onu arayabilir, demiştim.
jamescampbell

1

Https://askubuntu.com/a/516336 adresinde bir çözüm yolladım ve ayrıca çözümü buraya kopyalayıp yapıştıracağım.

Arka planda çalışan bıraktığım pyudev kullanarak bir Python betiği yazdım . Bu komut dosyası udev olaylarını dinler (böylece çok verimlidir) ve istediğim kodu çalıştırır. Benim durumumda, aygıtlarımı kurmak için komutlar çalışıyorxinput ( en son sürüme bağlantı ).

İşte aynı betiğin kısa bir versiyonu:

#!/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
Güzel bir senaryoya benziyor, +1. Önerebileceğim tek şey, sadece bir string yerine listeyi kullanmak call(). Bu şekilde, foobar.shbetiğe argüman sağlamak gerekirse , bunu dinamik olarak yapabilirsiniz.
Sergiy Kolodyazhnyy

1
Doğru tespit. Benim "gerçek" betiğim (cevaptan bağlanmış) bir liste kullanır. Buraya yapıştırdığım bu minimalist versiyonda, perişan oldum ve yanlışlıkla bir dize kullandım. Teşekkürler! Cevabı güncelledim.
Denilson Sá Maia

-1

Usb aygıtı takılıyken betiği çalıştırmak için aşağıdaki çözümü kullanıyorum:

Pendrive'ı veya başka bir usb depolama birimini biçimlendirin ve bunu yaparken bir isim verin. Sonra sıra /etc/rc.local eklels -q /dev/disk/by-label > /home/pi/label.txt

label.txt adında bir txt dosyası oluşturacaktır (başka bir ad olabilir)

daha sonra /etc/rc.local içinde tekrar 2 satır daha ekleyin:

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

Şimdi her seferinde USB_drive_name adında bir pendrive eklendiğinde script çalışacaktır.

Birkaç küçük değişiklikle, yukarıdaki çözelti sistem çalışırken ve çalışırken kullanılabilir.


Soruyu cevaplamıyor: Bu sadece önyükleme süresini kapsar (ve udevdiğer zamanlarda kullanmak "birkaç küçük değişiklik değildir") ve Ahududu Pi. Gereksiz sudo- rc.localkök olarak çalışıyor, ayrıcalık yükseltme sorunu - normal bir kullanıcı tarafından düzenlenebilir bir dosya kök olarak çalıştırılıyor.
Gert van den Berg,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.