如何通过运行命令执行与按下 nautilus 中的弹出按钮相同的操作?

如何通过运行命令执行与按下 nautilus 中的弹出按钮相同的操作?

我想通过运行命令来弹出设备(例如,可以将其分配给快捷键)。

我已经使用过udisksctl并且知道如何弹出驱动器,但这对于分配给键绑定不是很有用,因为。

  • 终端报告错误(我希望收到通知)
  • 成功的详细信息也会打印到终端(我想忽略它)

有没有办法运行一个命令来弹出通知错误的设备,就像我在 nautilus 中按下弹出按钮一样?

答案1

这是一个 Python 脚本,它将收集所有已安装的 USB 分区,并udisksctl unmount -b <DEV>在每个分区上执行。使其成为可用快捷方式的标准规则适用:确保脚本可执行并将脚本的完整路径作为命令。

根据要求,GUI 对话框中仅显示错误,不会显示其他输出。

#!/usr/bin/env python
import os
import subprocess
import sys

def run_cmd(cmdlist):
    """ utility: reusable function for running external commands """
    try:
        stdout = subprocess.check_output(cmdlist,stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as cpe:
        # GtkDialog error should be ignored. 
        if not "GtkDialog mapped without a transient parent" in cpe.output:
            return error_dialog(cpe.output," ".join(cmdlist))

def error_dialog(err_msg,called_cmd):
    """ Displays graphical error dialog and exits the script"""
    subprocess.call(['zenity','--error','--text',err_msg,'--title',called_cmd])
    sys.exit(1)

def find_usb_partitions():
    """ Constructs a list of USB partitions """
    return tuple( os.path.realpath(os.path.join("/dev/disk/by-path",p))
                  for p in os.listdir("/dev/disk/by-path")
                  if 'usb' in p and 'part' in p
    )  

def find_mounted_devs():
    devs=[]
    with open('/proc/mounts') as mounts:
         for line in mounts:
             dev = line.split()[0]
             if dev.startswith('/dev/'):
                 devs.append(dev)     
    return devs

def main():
   parts=find_usb_partitions()
   devs=find_mounted_devs()
   mounted_parts=tuple(i for i in parts if i in devs)
   for part in mounted_parts:
       run_cmd(['udisksctl', 'unmount', '-b',part])
       run_cmd(['udisksctl', 'power-off', '-b',part])

if __name__ == '__main__': main()

额外的想法

虽然脚本可以工作,但我发现从快捷方式卸载的想法有点多余。这样的任务至少需要用户参与。如果目标是能够在没有终端的情况下卸载,那么已经有办法做到这一点。例如,如果您是 Unity 用户,则启动器上已经有设备图标,您可以右键单击并弹出设备。我写过U盘指标,您可以使用它从图形指示器卸载分区(它使用了一些我在这个答案中使用的相同想法)。无论哪种情况,都有替代方案,但我个人建议不要使用快捷方式卸载东西。但话又说回来,这只是我的个人观点。

答案2

这是 @sergiy-kolodyazhnyy 的优秀答案的修改版,并进行了以下更改:

  • 不要检查part名称(我的某些驱动器不使用分区)。
  • 使用by-id而不是这样可以by-path减少歧义。p.startswith("usb-")
  • 在单独的回路中关闭电源(多个设备可能连接到同一电源)。
  • 关机前检查设备是否存在(再次链接电源)。
  • 运行命令(run_cmd)根据成功情况返回布尔值。
  • 通知最终结果(安装/卸载的设备数量)。
  • 使用 Python3(子进程以字节为单位输出)。

更新:使这个工具更加通用:
udisksctl_usb_all [--mount, --unmount, --unmount-power-off]
因此它可以用于所有 3 个操作。

#!/usr/bin/env python3
import os
import subprocess
import sys


def run_cmd(cmdlist):
    ''' utility: reusable function for running external commands '''
    try:
        stdout = subprocess.check_output(cmdlist, stderr=subprocess.STDOUT)
        return True
    except subprocess.CalledProcessError as cpe:
        print(cpe.output)
        # GtkDialog error should be ignored.
        if not b'GtkDialog mapped without a transient parent' in cpe.output:
            return error_dialog(cpe.output, ' '.join(cmdlist))
        return False


def error_dialog(err_msg, called_cmd):
    ''' Displays graphical error dialog and exits the script'''
    print(called_cmd)
    subprocess.call(['zenity', '--error', '--text', err_msg, '--title', called_cmd])
    sys.exit(1)


def find_usb_partitions():
    ''' Constructs a list of USB partitions '''
    return tuple(
        os.path.realpath(os.path.join('/dev/disk/by-id', p))
        for p in os.listdir('/dev/disk/by-id')
        if p.startswith('usb-')
    )


def find_mounted_devs():
    devs = []
    with open('/proc/mounts') as mounts:
        for line in mounts:
            if line.startswith('/dev/'):
                devs.append(line.split(' ', 1)[0])
    return devs


def unmount_all(power_off=False):
    unmount_len = 0
    parts = find_usb_partitions()
    devs = find_mounted_devs()
    mounted_parts = tuple(i for i in parts if i in devs)
    for part in mounted_parts:
        if run_cmd(['udisksctl', 'unmount', '-b', part]):
            unmount_len += 1

    if power_off:
        # Some drives may be linked regarding power, check each exists first.
        for part in mounted_parts:
            if os.path.exists(part):
                run_cmd(['udisksctl', 'power-off', '-b', part])

    if unmount_len:
        run_cmd(['notify-send', 'Unmounted {} file-systems!'.format(unmount_len)])
    else:
        run_cmd(['notify-send', 'Nothing to unmount!'])


def mount_all():
    mount_len = 0
    parts = find_usb_partitions()
    devs = find_mounted_devs()

    # only include non-numbered devices if numbered ones don't exist
    # don't try to mout /dev/sdc if /dev/sdc1 exists.
    parts_numbered = set()
    for p in parts:
        p_strip = p.rstrip('0123456789')
        if p != p_strip:
            parts_numbered.add(p_strip)
    parts = tuple(p for p in parts if p not in parts_numbered)
    del parts_numbered

    unmounted_parts = tuple(i for i in parts if i not in devs)
    for part in unmounted_parts:
        if run_cmd(['udisksctl', 'mount', '-b', part]):
            mount_len += 1

    if mount_len:
        run_cmd(['notify-send', 'Mounted {} file-systems!'.format(mount_len)])
    else:
        run_cmd(['notify-send', 'Nothing to mount!'])


if __name__ == '__main__':
    if "--mount" in sys.argv:
        mount_all()
    elif "--unmount" in sys.argv:
        unmount_all(power_off=False)
    elif "--unmount-power-off" in sys.argv:
        unmount_all(power_off=True)
    else:
        print("Expected one of ['--mount', '--unmount' or '--unmount-power-off'] to be passed.")

答案3

另一种方法是使用 umount 命令:sudo umount /media/user/your-usb-drive

要确定正确的驱动器,您可以使用 mount 命令:mount | grep usb

相关内容