当外部驱动器在 WSL 中可用时,有没有办法安装它?

当外部驱动器在 WSL 中可用时,有没有办法安装它?

我在 WSL 中使用 Ubuntu,并使用 zsh/bash shell。我的主机操作系统是 Windows 10。我已经弄清楚了如何安装 Windows 外部驱动器

sudo mkdir /mnt/d
sudo mount -t drvfs D: /mnt/d

我很少插入此驱动器,因此我希望在插入时自动安装它。如果在插入驱动器后发生这种情况,则没问题,然后启动一个新的 WSL 终端。

我不想把这个命令放在某种.bashrc文件中,因为每次打开终端时都要输入密码,这太麻烦了,尤其是如果 99% 的情况下命令都会失败。把它放在 bash 脚本中也没什么用,因为我很少运行它,等到我需要使用它的时候,我就会忘记我一开始创建了它。

那么,当外部驱动器在 WSL 中可用时,有没有办法安装它?


我不知道这是否是一个好的解决方案,但这会告诉你如何关闭 sudo 的密码请求。这是我采取的路线:https://superuser.com/a/1492456/89165

答案1

在我看来,这需要两种不同的方法:

  • 首先,我们需要处理驱动器已连接时 WSL 启动的情况。
  • 而且我们还需要处理当 WSL 已在运行时连接驱动器的情况。

WSL 启动时驱动器已连接

第一部分应该相当简单。

我不想把这个命令放在 .bashrc 类型的文件中,因为每次打开终端时都要输入密码

这很容易解决。将以下内容添加到您的~/.bashrc

wsl.exe -u root -e mount -t drvfs D: /mnt/d > /dev/null 2>&1

如果驱动器可用,则将安装该驱动器。如果不可用,则将默默失败。

WSL 运行时驱动器已连接

这并不容易,并且可能需要更多的错误处理才能“健壮”,但我能够通过创建 PowerShell 脚本来使其工作:

  • 当 USB 驱动器连接时注册操作
  • wsl -u root -e mount -t drvfs /mnt/<driveletter> <Drive>事件触发时运行。
$query = "select * from __InstanceCreationEvent within 5 where TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 2"

$action = {
    $drivePath = $event.SourceEventArgs.NewEvent.TargetInstance.Name
    $driveLetter = $drivePath.ToLower()[0]
    wsl -u root -e mount -t drvfs $drivePath /mnt/$driveLetter
}

Register-WmiEvent -Query $Query -Action $Action -SourceIdentifier USBFlashDriveWSLMount

请注意,由于它使用了,因此需要在 Windows PowerShell(而不是 PowerShell Core)中运行WMIEvent。我确信有一个使用 CIM 的 PowerShell Core 等效程序,但我还没有尝试过这种方式。

如果遇到问题,请检查输出。从 PowerShell:

Get-Job
# Get the Id of the job then
Receive-Job <job_id>

理论上,您可以通过任务计划程序将此脚本设置为在 Windows 登录时运行,但我还没有尝试过。我有 80% 的信心它会起作用。您需要通过命令调用它powershellpwsh因为它使用 WMIEvent,所以不需要)。

请注意,显然还有一种方法可以通过 CIM 永久注册事件侦听器。上周我花了一些时间研究这个问题,但当我按照一些文档操作时,却发现在我的系统上创建了一个我无法摆脱的 CIM 类,于是就陷入了困境。我可能最终会回到这个问题上,但希望这对您来说可以作为计划任务。我只是不想等到我“恰到好处”时才发布,因为我可能永远也做不完。

答案2

这 1 行代码将删除 sudo 的密码请求。

sudo sed -i 's|^%sudo.*$|%sudo    ALL=(ALL:ALL) NOPASSWD: ALL|' -i /etc/sudoers

这 1 行代码将列出未安装的驱动器。

echo -e "$(cmd.exe /C "wmic logicaldisk get name" 2>/dev/null | sed '1d;$d')\n$(mount | grep drvfs | sed 's|\(^.:\).*|\1|')" | tr '\r' ' ' |sed 's| ||g' | sort | uniq -u

因此,我们可以定义一个函数~/.bashrc或创建一个 bash 脚本来挂载它们。您可以自行决定是手动调用该函数还是将其添加到~/.bashrc

mountext(){ # Find unmounted windows drives and mount them.
    ds=$(echo -e "$(cmd.exe /C "wmic logicaldisk get name" 2>/dev/null | sed '1d;$d')\n$(mount | grep drvfs | sed 's|\(^.:\).*|\1|')" | tr '\r' ' ' |sed 's| ||g' | sort | uniq -u | cut -c1)
    if [ ! $ds = $'\n' ] || [ ! -z "${ds}" ]; then
        for d in $ds; do
        sudo bash -c "mkdir -p /mnt/${d,} && mount -t drvfs ${d}: /mnt/${d,}"
        echo "Mounted drive ${d}: at /mnt/${d,}." 
        done
        else echo "No drives to mount."
    fi
}

答案3

此命令:

cmd.exe /C "wmic logicaldisk get name"

将显示网络安装以及实际上未加载媒体的驱动器号。例如,我有一个多格式存储卡读卡器,它保留了五个驱动器号(每个插槽一个,例如 SD、micro-SD 等),即使没有安装卡,此查询也会返回所有这些驱动器号。因此,我使用以下命令获取其中有媒体的本地驱动器号:

powershell.exe -Command "gdr -PSProvider 'FileSystem'"|grep '[0-9]\+'|grep -o '[A-Z]:'

假设您的路径中有 powershell.exe 并以 sudo 身份运行。

第一个 grep 语句选择文件系统列表中显示可用空间的行(即已安装媒体的代理);第二个 grep 只是在末尾提取驱动器号。您应该能够将此输出输入到上面提供的相同脚本中,以便在 WSL 中安装为 drvfs。

总而言之,您可以以 root 身份将其作为 cronjob 运行:

#!/bin/bash
ds=$(echo -e "$(powershell -Command "gdr -PSProvider 'FileSystem'"|grep '[0-9]\+'|grep -o '[A-Z]:' 2>/dev/null | sed '1d;$d')\n$(mount | grep drvfs | sed 's|\(^.:\).*|\1|')" | tr '\r' ' ' |sed 's| ||g' | sort | uniq -u | cut -c1)
if [ ! $ds = $'\n' ] || [ ! -z "${ds}" ]; then
  for d in $ds; do
    bash -c "mkdir -p /mnt/${d,} && mount -t drvfs ${d}: /mnt/${d,}"
    echo "Mounted drive ${d}: at /mnt/${d,}."
  done
else echo "No drives to mount."
fi

相关内容