如何以编程方式确定根分区的设备名称/基本名称?

如何以编程方式确定根分区的设备名称/基本名称?

参考:以下问题 驱动器名称? “/dev/sda”的“sda”部分的正确术语是什么?

鉴于:

  1. 我有一个系统(在本例中是 Raspberry Pi,但这可能与任何 'nix 系统相关。)
  2. 它正在运行一个 Linux 版本,并且可以假设所有正常的 Linux 命令都可以工作。
  3. 启动设备可以是 SD 卡或 USB 连接存储设备。
  4. 如果从连接的存储设备启动,则设备“基本名称”为 sd(x)
  5. 如果从 SD 卡启动,设备“basename”将变为类似“mm(xxxx)”

我想要做什么:我希望能够以编程方式(如果可能的话,在 shell 脚本中)启动它的设备类型,并根据启动设备更改某些特征。

简单的例子:

Boot device = "mmxxxxx"
   Print "Booted from SD card!"
Boot device = "sda"
   Print "Booted from Attached Storage!"

我想要做的是提取根分区所源自的主要设备类型(为了需要一个更好的术语)(IE“sd”、“mm”或其他任何名称,具体取决于安装为根分区的设备。)

我怀疑我可以以某种方式列出安装在根目录上的设备,没有列出所有内容mount,然后提取最后一个斜杠后面的前两个字母。 。 。

答案1

挂载点由 systemd 控制。

您可以通过以下方式列出 systemd 挂载单元文件:

systemctl list-units --type=mount --all

示例输出:

  -.mount                       loaded    active   mounted Root Mount                                   
  boot-efi.mount                loaded    active   mounted /boot/efi
...

根分区由 控制-.mount

systemctl status -- -.mount

● -.mount - Root Mount
     Loaded: loaded (/etc/fstab; generated)
     Active: active (mounted) since Wed 2024-02-07 
      Where: /
       What: /dev/sdaX
       Docs: man:fstab(5)
             man:systemd-fstab-generator(8)

要提取设备名称:

systemctl status -- -.mount |grep -oP '(?<=What: ).*' |xargs basename

更好,正如指出的那样@steeldriver在这个评论:

systemctl show --value --property=What -- -.mount |xargs basename

男人systemd.mount

What:获取要挂载的设备节点、文件或其他资源的绝对路径。

答案2

这是一个不依赖于Linux的答案系统(需要/sys安装才能lsblk使用以及jq解析结果的命令)。

知道它lsblk已经包含了找出树输出中的依赖关系的所有逻辑,我想知道如何利用它来完成任务。使用--inverse首先显示叶子(但还不能将叶子作为参数),以便/首先使用安装点进行过滤。然后--json可以迭代找到结果。

它输出最终的设备名称,绕过 LVM、LUKS 等的任何层(在磁盘分区中使用 / over LV over LUKS 的系统进行测试)。未使用 RAID 进行测试(我希望输出多个设备,否则此jq脚本将失败)。

这是一条很长的线:

lsblk --json --tree --inverse | jq -r '.blockdevices[] | if .mountpoints[] == "/" then ( .. | if .children? then empty else if .name then .name else empty end end ) else empty end'

或者更容易阅读:

lsblk --json --tree --inverse |
    jq -r '
.blockdevices[] |
    if .mountpoints[] == "/" then
        .. |
            if .children? then
                empty
            else
                .name // empty
            end
    else
        empty
    end
'

它接受第一个匹配项,/并将..在对象上递归(使用 ),直到它们不再包含子对象(也称为"children",唯一类型的子对象),这意味着它是目标设备,然后显示其名称。

要仅获取结果的前 2 个字符,只需附加一个额外的| cut -c-2.

答案3

用于df /获取 的设备/。您也可以按列 ( --output=source) 和行 ( tail -1) 进行过滤:

% df --output=source / | tail -1
/dev/mapper/sys-root

答案4

这是一个简单的方法。我只在我自己的机器上对此进行了测试,您的安装命令可能有不同的输出。

boot_device=( $(mount | grep boot) )
if [[ $(echo "${boot_device[0]}" | grep -c sd) -eq 1 ]]
then
echo "Booted from attached storage"
else 
echo "Booted from SD card!"
fi

您可以使用 elif 结构来代替 else,例如:

elif [[ $(echo "${boot_device[0]}" | grep -c mm) -eq 1 ]]
then
echo "Booted from SD card!"
else
echo "ERROR: Something has gone horribly wrong!"
fi

您已经接受了答案,但由于我花了几分钟弄清楚如何使用 mount 命令执行此操作,因此我将其作为答案发布。

相关内容