检查Bash脚本中是否挂载了卷的最佳方法是什么?
我真正想要的是一种可以像这样使用的方法:
if <something is mounted at /mnt/foo>
then
<Do some stuff>
else
<Do some different stuff>
fi
/etc/mtab
,/proc/mounts
被链接到/proc/self/mounts
。(至少是Fedora 20)
检查Bash脚本中是否挂载了卷的最佳方法是什么?
我真正想要的是一种可以像这样使用的方法:
if <something is mounted at /mnt/foo>
then
<Do some stuff>
else
<Do some different stuff>
fi
/etc/mtab
,/proc/mounts
被链接到/proc/self/mounts
。(至少是Fedora 20)
Answers:
避免使用,/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
。)
if mountpoint -q /mnt/foo
then
echo "mounted"
else
echo "not mounted"
fi
要么
mountpoint -q /mnt/foo && echo "mounted" || echo "not mounted"
mountpoint
源自Ubuntu / Debian中的“ initscripts”包。
mountpoint
在于,它实际上会检查是否已安装安装点,而不是是否已安装设备。如果通过-x
选项传递设备,它将告诉您主要/次要设备号,但不会告诉您是否已安装。
util-linux
findmnt -rno SOURCE,TARGET "$1"
避免了其他答案中的所有问题。它只用一个命令就可以完成这项工作。
其他方法也有这些缺点:
grep -q
并且grep -s
是多余的步骤,并非所有地方都支持。/proc/\*
并非到处都受支持。mountinfo
基于/ proc /。cut -f3 -d' '
弄乱路径名中的空格..列表模式仅用于向后兼容。
对于更健壮和可定制的输出,请使用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
findmnt(8)
命令,但从未真正使用它。坦白说,如果我要更新一些在Linux机器上(或可使用命令的地方)执行此类操作(或制作新脚本)的脚本,这就是我要做的。
findmnt
必须提供参数--source encfs
,否则它将始终考虑要挂载的目录,因为它会退回到父挂载。
grep
解决方案更好,因为如果安装路径怪异,则可能会出现误报:例如,如果我安装/dev/mmcblk0p1
在上~/mnt/dev/sda1
,则可能会错误地/dev/sda1
通过command进行安装mount | grep '/dev/sda1'
。我不会使用产生误报findmnt
。好答案!
像这样的脚本永远不会移植。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会告诉您有用的信息。
以下是我在我的rsync备份cron作业之一中使用的内容。它会检查是否已安装/ backup,并尝试未安装/ backup(它可能会失败,因为驱动器位于热插拔托架中,甚至可能不存在于系统中)
注意:以下内容仅在linux上有效,因为它会干扰/ proc / mounts-更便携的版本将运行'mount | grep / backup”,如Matthew的回答。
如果!grep -q / backup / proc / mounts; 然后 如果!挂载/备份; 然后 回声“失败” 1号出口 科幻 科幻 回声“成功”。 #在这里做东西
grep -q ' /backup ' /proc/mounts
或mount | grep -q ' /backup '
。或者,如果您的grep不支持-q
,则重定向到/ dev / null (这几天在grep的POSIX规范中)。
由于要进行挂载,无论如何都需要在该目录中挂载一个目录,因此我的策略始终是创建一个伪造的文件,并使用一个永远不会使用的奇怪文件名,然后检查它是否存在。如果文件在那里,那么那个地方什么都不会挂载...
我认为这不适用于安装网络驱动器或类似的东西。我将其用于闪存驱动器。
比较设备编号怎么样?我只是想着最深奥的方式。
#!/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也将显示错误。
这些都不满足用例,其中给定目录是另一个安装点内的子目录。例如,您可能将/ 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外部镜像安装点,那么这将非常有用。
尽管这是一个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
-q
它-s
是由POSIX指定的,因此无论如何它都不会有任何可移植性问题(现在如果不是以前-我没有跟踪何时发生什么更改)。
是否需要比这更复杂?
mount \
| cut -f 3 -d ' ' \
| grep -q /mnt/foo \
&& echo "mounted" || echo "not mounted"
grep -q /mnt/foo
也将匹配安装点/mnt/food
和/not/mnt/foo
...怎么样grep -qx /mnt/foo
?
-x
仅当整行匹配时,才使grep匹配。
cut -f 3 -d ' '
挂载路径在文件名中包含空格时会迷路。
我必须在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
。