检查Bash脚本中是否挂载了卷的最佳方法是什么?


103

检查Bash脚本中是否挂载了卷的最佳方法是什么?

我真正想要的是一种可以像这样使用的方法:

if <something is mounted at /mnt/foo> 
then
   <Do some stuff>
else
   <Do some different stuff>
fi

我正要写一个脚本来自己做。我的第一个想法是从/ etc / mtab中获取信息,但是我还没有翻阅bash书籍,看看是否还有更直接的方法。
09年

@ 3dinfluence -是的,我知道这一点,从很久以前,但是/etc/mtab/proc/mounts被链接到/proc/self/mounts(至少是Fedora 20)
Wilf 2014年

服务器故障堆栈溢出以及Unix和Linux堆栈交换也存在类似的问题。
萨沙

Answers:


113

避免使用,/etc/mtab因为它可能不一致。

避免管道,mount因为它不必那么复杂。

只是:

if grep -qs '/mnt/foo ' /proc/mounts; then
    echo "It's mounted."
else
    echo "It's not mounted."
fi

(后面的空格/mnt/foo是为了避免匹配,例如/mnt/foo-bar。)


7
更不用说,如果安装点被楔入,对挂载的调用可能会挂起。
乍得·休尼卡特

8
适用于linux,不适用于freebsd或solaris。
克里斯,

4
克里斯,这是真的。虽然这个问题被标记为linux。
丹·卡利

3
我猜这是一个哲学问题-我们应该尝试使事物具有可移植性,还是应该假设世界上所有正在运行的Windows / Linux并采取相应措施?
克里斯,

18
实际上,您应该测试'/ mnt / foo',即。带有空格,否则如果安装了名为eg的卷,则可能会得到误报。“傻瓜”。我刚遇到两个安装点“ lmde”和“ lmde-home”的问题。
marlar 2011年

58
if mountpoint -q /mnt/foo 
then
   echo "mounted"
else
   echo "not mounted"
fi

要么

mountpoint -q /mnt/foo && echo "mounted" || echo "not mounted"

4
仅供参考:mountpoint源自Ubuntu / Debian中的“ initscripts”包。
2012年

1
没为我工作-:-(
Wilf

这是我的流浪者挂断的电话。
dhill

问题mountpoint在于,它实际上会检查是否已安装安装点,而不是是否已安装设备。如果通过-x选项传递设备,它将告诉您主要/次要设备号,但不会告诉您是否已安装。
vegatripy

@blueyed在Debian Buster中,它是由软件包提供的util-linux
elboulangero

18

findmnt -rno SOURCE,TARGET "$1"避免了其他答案中的所有问题。它只用一个命令就可以完成这项工作。


其他方法也有这些缺点:

  • grep -q并且grep -s是多余的步骤,并非所有地方都支持。
  • /proc/\* 并非到处都受支持。
  • mountinfo 基于/ proc /。
  • cut -f3 -d' ' 弄乱路径名中的空格
  • 解析mount的空白是有问题的。它的手册页现在说:

..列表模式仅用于向后兼容。

对于更健壮和可定制的输出,请使用findmnt(8),尤其是在脚本中。


重击功能:

#These functions return exit codes: 0 = found, 1 = not found

isMounted    () { findmnt -rno SOURCE,TARGET "$1" >/dev/null;} #path or device
isDevMounted () { findmnt -rno SOURCE        "$1" >/dev/null;} #device only
isPathMounted() { findmnt -rno        TARGET "$1" >/dev/null;} #path   only

#where: -r = --raw, -n = --noheadings, -o = --output

用法示例:

if isPathMounted "/mnt/foo bar";      #Spaces in path names are ok.
   then echo "path is mounted"
   else echo "path is not mounted"
fi

if isDevMounted "/dev/sdb4"; 
   then echo "device is mounted"
   else echo "device is not mounted"
fi

#Universal:
if isMounted "/mnt/foo bar"; 
   then echo "device is mounted"
   else echo "device is not mounted"
fi

if isMounted "/dev/sdb4";
   then echo "device is mounted"
   else echo "device is not mounted"
fi

1
无论如何,对于特定于Linux的用户,这实际上是最好的方法。我已经看过该findmnt(8)命令,但从未真正使用它。坦白说,如果我要更新一些在Linux机器上(或可使用命令的地方)执行此类操作(或制作新脚本)的脚本,这就是我要做的。
Pryftan

1
请注意,对于encfs,findmnt必须提供参数--source encfs,否则它将始终考虑要挂载的目录,因为它会退回到父挂载。
Burkart

这也比grep解决方案更好,因为如果安装路径怪异,则可能会出现误报:例如,如果我安装/dev/mmcblk0p1在上~/mnt/dev/sda1,则可能会错误地/dev/sda1通过command进行安装mount | grep '/dev/sda1'。我不会使用产生误报findmnt。好答案!
Cody Piersall

7

像这样的脚本永远不会移植。unix中一个肮脏的秘密是,只有内核知道什么文件系统在哪里,而缺少/ proc(不可移植)之类的东西,它永远不会给您一个直接的答案。

我通常使用df来发现子目录的挂载点及其所在的文件系统。

例如(需要posix shell,例如ash / AT&T ksh / bash等)

case $(df  $mount)
in
  $(df  /)) echo $mount is not mounted ;;
  *) echo $mount has a non-root filesystem mounted on it ;;
esac

Kinda会告诉您有用的信息。


1
这个问题被标记为linux,所以也许它不一定是可移植的
Rory

6

以下是我在我的rsync备份cron作业之一中使用的内容。它会检查是否已安装/ backup,并尝试未安装/ backup(它可能会失败,因为驱动器位于热插拔托架中,甚至可能不存在于系统中)

注意:以下内容仅在linux上有效,因为它会干扰/ proc / mounts-更便携的版本将运行'mount | grep / backup”,如Matthew的回答。

  如果!grep -q / backup / proc / mounts; 然后
    如果!挂载/备份; 然后
      回声“失败”
      1号出口
    科幻
  科幻
  回声“成功”。
  #在这里做东西

2
被推荐为良好的健康检查替代方案。
丹·卡利

大概这种方法遇到了与马修·布洛赫(Matthew Bloch)的答案相同的问题。
mwfearnley '18

是的,除了“ Eliptical view”提到的文件名空间问题(这使整行,而不仅仅是提取的字段)。除非您以某种方式忘记引号是您可以做的事情,否则子字符串问题并不重要。例如grep -q ' /backup ' /proc/mountsmount | grep -q ' /backup '。或者,如果您的grep不支持-q重定向到/ dev / null (这几天在grep的POSIX规范中)。
cas

2

由于要进行挂载,无论如何都需要在该目录中挂载一个目录,因此我的策略始终是创建一个伪造的文件,并使用一个永远不会使用的奇怪文件名,然后检查它是否存在。如果文件在那里,那么那个地方什么都不会挂载...

我认为这不适用于安装网络驱动器或类似的东西。我将其用于闪存驱动器。


2

比较设备编号怎么样?我只是想着最深奥的方式。

#!/bin/bash
if [[ $(stat -c "%d" /mnt) -ne $(stat -c "%d" /mnt/foo) ]]; then
    echo "Somethin mounted there I reckon"
fi

我的逻辑上有一个缺陷...

作为功​​能:

#!/usr/bin/bash
function somethingMounted {
        mountpoint="$1"
        if ! device1=$(stat -c "%d" $mountpoint); then
                echo "Error on stat of mount point, maybe file doesn't exist?" 1>&2
                return 1
        fi
        if ! device2=$(stat -c "%d" $mountpoint/..); then
                echo "Error on stat one level up from mount point, maybe file doesn't exist?" 1>&2
                return 1
        fi

        if [[ $device1 -ne $device2 ]]; then
                #echo "Somethin mounted there I reckon"
                return 0
        else
                #echo "Nothin mounted it seems"
                return 1
        fi
}

if somethingMounted /tmp; then
        echo "Yup"
fi

回显错误消息可能是多余的,因为stat也将显示错误。


实际上,可能必须首先为每个调用检查stat的退出状态,以确保文件在那里...不像我想的那样新颖:-(
Kyle Brandt

1

这些都不满足用例,其中给定目录是另一个安装点内的子目录。例如,您可能将/ thing托管到NFS:/ real_thing。为此,不能在/ proc / mounts / etc / mtab或'mount'上使用grep,因为您将查找不存在的挂载点。例如,/ thing / thingy不是挂载点,但是/ thing挂载在host:/ real_thing上。实际上,这里投票的最佳答案不是“确定目录/卷是否已安装的最佳方法”。我赞成使用'df -P'(-P POSIX标准模式)作为更清洁的策略:

dev=`df -P /thing/thingy | awk 'BEGIN {e=1} $NF ~ /^\/.+/ { e=0 ; print $1 ; exit } END { exit e }'` && {
    echo "Mounted via: $dev"
} || {
    echo "Not mounted"
}

运行此命令的输出将是:

Mounted via: host:/real_thing

如果您想知道真正的挂载点是什么,那么没问题:

mp=`df -P /thing/thingy | awk 'BEGIN {e=1} $NF ~ /^\/.+/ { e=0 ; print $NF ; exit } END { exit e }'` && {
    echo "Mounted on: $mp"
} || {
    echo "Not mounted"
}

该命令的输出将是:

Mounted on: /thing

如果您尝试创建某种类型的chroot,以通过任意目录或文件列表在chroot中的chroot外部镜像安装点,那么这将非常有用。


1

很抱歉提出这个问题,但我认为这非常有用:

if awk '{print $2}' /proc/mounts | grep -qs "^/backup$"; then
    echo "It's mounted."
else
    echo "It's not mounted."
fi

这将获得/ proc / mounts的第二列(第二列=安装点)。

然后,它抓住输出。注意^和$,这可以防止/ backup与/ mnt / backup或/ backup-old等匹配。


0

grep / etc / mtab可能是您的挂载点?


1
mtab可能会过期,或者根本无法通过mount进行更新,例如,当您使用mount -n时,因为/是只读的。
克里斯,

我同意,但这似乎是开始寻找的第一个地方。
Ophidian


0

尽管这是一个Linux问题,但为什么不做起来就容易移植呢?

的手册页中grep说:

可移植的shell脚本应避免同时使用-q和-s,而应将标准和错误输出重定向到/dev/null

因此,我提出以下解决方案:

if grep /mnt/foo /proc/mounts > /dev/null 2>&1; then
        echo "Mounted"
else
        echo "NOT mounted"
fi

3
许多UNIX系统不提供/ proc文件系统
Dmitri Chubarov 2012年

@DmitriChubarov确实。是什么使可移植性的概念具有讽刺意味?也许这是一个较新的更新,但是-q-s是由POSIX指定的,因此无论如何它都不会有任何可移植性问题(现在如果不是以前-我没有跟踪何时发生什么更改)。
Pryftan

0

是否需要比这更复杂?

mount \
    | cut -f 3 -d ' ' \
    | grep -q /mnt/foo \
  && echo "mounted" || echo "not mounted"

1
grep -q /mnt/foo也将匹配安装点/mnt/food/not/mnt/foo...怎么样grep -qx /mnt/foo
rakslice 2012年

@rakslice:那是行不通的。-x仅当整行匹配时,才使grep匹配。
mivk 2012年

1
cut -f 3 -d ' '挂载路径在文件名中包含空格时会迷路。
椭圆视图

0

取决于您对要检查的卷的了解。

在我最近研究的特定案例中,我担心要查找是否安装了特定的闪存驱动器,最容易起作用的是检查/ dev / disks / by-label /的存在。如果已插入设备,则udev脚本将确保链接存在(并且在拔出设备时将其删除)。

(这不是一个高度可移植的答案;不过,它可以在许多现代Linux发行版中使用,并且该问题针对Linux进行了标记,与迄今为止提到的任何方法完全不同,因此扩展了可能性。)


0

在您的mountpoint下创建文件check_mount,然后仅测试它是否存在?

if [[ -f /something/check_mount ]]; then
   echo "Mounted
   RC=$?
else
   Echo "Not mounted"
   RC=0
fi
exit $RC

-1

我必须在Chef中进行幂等操作,因为当Chef-client运行时,由于已安装了卷,因此运行将失败。在我撰写本文时,Chef mount资源存在某种错误,无法按我所需的方式使用属性,因此我改用该execute资源装入卷。这是我的操作方式:

if not node['docker-server']['mountpoint'] == "none"
  execute "set up mount" do
    user "root"
    command "mount -t ext4 #{node['docker-server']['mountpoint']} #{node['docker-server']['data-dir']}"
    not_if "grep -qs #{node['docker-server']['data-dir']} /proc/mounts"
  end
end

如有任何混淆,我的属性文件中包含以下内容:

default['docker-server']['mountpoint'] = "/dev/vdc"
default['docker-server']['data-dir'] = "/data"

if not node['docker-server']['mountpoint'] == "none"case语句的一部分,其中,如果未指定服务器上的安装点,则安装点默认为none


...这与原始问题有什么关系?!?
Massimo 2015年

我的厨师食谱评论与原始问题之间的关系是,人们越来越倾向于自动化。因此,如果有人来这里想知道如何在厨师食谱中进行这项工作,他们将提供答案。在生活中,有两种选择:1)做到最低限度并使一些人快乐,以及2)多加努力。因此,不要将我的帖子记下来,而是接受它的含义:支持已接受答案的其他信息。
KLaw 2015年

问题是关于bash脚本,您的答案是关于Chef脚本。尽管它可能对某人有用,但与该问题没有任何关系。
Massimo

@KLaw '因此,与其将我的帖子记下来,不如按原样接受:支持已接受答案的其他信息。我同意,我也不是通常不赞成投票的人(我也没有在这里投反对票),但是如果您对这类事情有疑问,应该将其添加为其他观点的补充吗?可能会保存其他注释。但是对于自动化,这正是bash脚本所允许的,所以我看不到您的意思。当然,我
体内
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.