我想通过运行命令来弹出设备(例如,可以将其分配给快捷键)。
我已经使用过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