Bash:迭代地挂载匹配命名方案的第一个驱动器,卷或分区,忽略第二个和后续匹配



我想:

  1. 遍历list;
  2. 查找第一个匹配子字符串的实例;
  3. 做点什么;
  4. 忽略任何后续匹配。
  5. 继续到列表末尾。

更具体:

#! /bin/bash
target_ORG=$(ls /usr/local/etc/ini/system/ORG)
target_DOMAIN=$(ls /usr/local/etc/ini/system/DOMAIN)
target_SITE=$(ls /usr/local/etc/ini/system/SITE)
target_DEVICE=$(ls /usr/local/etc/ini/system/DEVICE)
target_VOLUME=$(ls /usr/local/etc/ini/system/VOLUME)
target_HOST=$(ls /usr/local/etc/ini/system/HOST)

instanceList=$(ls /dev/disk/by-partlabel)
for i in $instanceList 

do
instance_ORG=${i:0:3}
instance_DOMAIN=${i:4:3}
instance_SAN=${i:8:1}
instance_SITE=${i:10:1}
instance_DEVICE=${i:12:5}
instance_VOLUME=${i:18:6}

<PSEUDOCODE>

Compare the instance_* strings with the target_* strings
IF they all match
THEN
mount $i /path/to/mountpoint
</PSEUDOCODE>
done

地点:

  1. 可用的特定设备随时间而变化

  2. partlabel格式为:xxx-xxx-x- xxx-xxxxxx(例如001-001-1-1-00001-000001),表示该磁盘分区为ORG-DOMAIN-SAN-SITE-DEVICE-VOLUME

  3. /usr/local/etc/ini/system/*目录每个都包含一个以相应子字符串命名的文件-允许通过简单地重命名(而不是必须操作内容)文件

    进行更改
  4. /path/to/mountpoint是匹配$instance_SAN的挂载点

That is ... 
xxx-xxx-1-x-xxxxx-xxxxxx mounts to /path/to/1
xxx-xxx-2-x-xxxxx-xxxxxx mounts to /path/to/2
xxx-xxx-3-x-xxxxx-xxxxxx mounts to /path/to/3


for循环的问题是,当我希望它保留第一个找到的实例时,它会简单地将下一个值赋给$instance_*变量——因此,xxx-xxx-1-1-xxxx -xxxxxx将被xxx-xxx- 1-2-xxxxxx -xxxxxx覆盖,以此类推。


一个case测试将查找并保留第一个找到的实例,但不会遍历$instanceList

e.g. given
/usr/local/etc/ini/system/ORG/001
/usr/local/etc/ini/system/DOMAIN/001
/usr/local/etc/ini/system/SITE/1
/usr/local/etc/ini/system/DEVICE/00001
/usr/local/etc/ini/system/VOLUME/000001
/usr/local/etc/ini/system/HOST/000001
...and...
*$instanceList* of:
001-001-1-1-00001-000001
001-001-1-1-00001-000002
001-001-1-2-00001-000001
001-001-1-2-00001-000002
001-001-2-2-00001-000001
001-001-2-2-00002-000001
001-001-3-5-00001-000002
001-001-1-1-00001-000001 will get mounted to /path/to/1
and everything else will be ignored.


我需要挂载第一个匹配设备,并忽略任何其他匹配的$instance_SAN,同时继续遍历$ instance_list。

e.g. given the above 
001-001-1-1-00001-000001 should be mounted to /path/to/1
001-001-1-1-00001-000002 should be ignored
001-001-1-2-00001-000001 should be ignored
001-001-1-2-00001-000002 should be ignored
001-001-2-2-00001-000001 should be mounted to /path/to/2
001-001-2-2-00002-000001 should be ignored
001-001-3-5-00001-000002 should be mounted to /path/to/3


嵌套如果测试太脆弱。

多个大小写测试可以工作

<PSEUDOCODE>

Case of $instance_SAN=1: mount device/partion to /path/to/$instance_SAN
Case of $instance_SAN=2: mount device/partion to /path/to/$instance_SAN
Case of $instance_SAN=3: mount device/partion to /path/to/$instance_SAN
</PSEUDOCODE>

但我只是不能围绕如何迭代$instanceList而不简单地在第一次匹配后中断。

我知道这可能是非常基本的,但是我的bash恐怕不是很高级。

但是,我希望避免使用诸如autoFS这样的解决方案,以便该方法不依赖于核心Linux安装以外的任何东西;即使是像最小的Arch/Gentoo,甚至是LFS这样的东西,也应该能够在不需要任何额外的实用程序的情况下提供一切——而且,这必须在登录前完成,所以,我不认为"第三方"解决方案会起作用。

= = = = = = =
更新
= = = = = = =

按照建议,通过pjh,尝试mountpoint || mount
#! /bin/bash
target_ORG=$(ls '/usr/local/etc/ini/system/ORG')
target_DOMAIN=$(ls 'usr/local/etc/ini/system/DOMAIN')
target_SITE=$(ls '/usr/local/etc/ini/system/SITE')
target_DEVICE=$(ls '/usr/local/etc/ini/system/DEVICE')
target_VOLUME=$(ls '/usr/local/etc/ini/system/VOLUME')
target_HOST=$(ls '/usr/local/etc/ini/system/HOST')

echo "target_ORG=$target_ORG"
echo "target_DOMAIN=$target_DOMAIN"
echo "target_SITE=$target_SITE"
echo "target_DEVICE=$target_DEVICE"
echo "target_VOLUME=$target_VOLUME"
echo "target_HOST=$target_HOST"

instanceList=$(ls /dev/disk/by-partlabel)

for i in {1..3}
do
for n in $instanceList 
do
echo -e 'n'
echo "i = $i"
echo "n = $n"
instance_ORG=${n:0:3}
instance_DOMAIN=${n:4:3}
instance_SAN=${n:8:1}
instance_SITE=${n:10:1}
instance_DEVICE=${n:12:5}
instance_VOLUME=${n:18:6}
mountpoint "/mnt/test/$i" || mount "$n" "/mnt/test/$i"
done
done


…结果

target_ORG=000
target_DOMAIN=000
target_SITE=1
target_DEVICE=00000
target_VOLUME=000001
target_HOST=000001

i = 1
n = 000-000-1-1-00000-000001
/mnt/test/1 is not a mountpoint
mount: /mnt/test/1: special device 000-000-1-1-00000-000001 does not exist.
i = 1
n = 000-000-2-1-00000-000001
/mnt/test/1 is not a mountpoint
mount: /mnt/test/1: special device 000-000-2-1-00000-000001 does not exist.
i = 1
n = 000-000-3-1-00000-000001
/mnt/test/1 is not a mountpoint
mount: /mnt/test/1: special device 000-000-3-1-00000-000001 does not exist.

i = 2
n = 000-000-1-1-00000-000001
/mnt/test/2 is not a mountpoint
mount: /mnt/test/2: special device 000-000-1-1-00000-000001 does not exist.
i = 2
n = 000-000-2-1-00000-000001
/mnt/test/2 is not a mountpoint
mount: /mnt/test/2: special device 000-000-2-1-00000-000001 does not exist.
i = 2
n = 000-000-3-1-00000-000001
/mnt/test/2 is not a mountpoint
mount: /mnt/test/2: special device 000-000-3-1-00000-000001 does not exist.

i = 3
n = 000-000-1-1-00000-000001
/mnt/test/3 is not a mountpoint
mount: /mnt/test/3: special device 000-000-1-1-00000-000001 does not exist.
i = 3
n = 000-000-2-1-00000-000001
/mnt/test/3 is not a mountpoint
mount: /mnt/test/3: special device 000-000-2-1-00000-000001 does not exist.
i = 3
n = 000-000-3-1-00000-000001
/mnt/test/3 is not a mountpoint
mount: /mnt/test/3: special device 000-000-3-1-00000-000001 does not exist.

但是它们确实存在——这可以通过简单地手动将它们挂载到相同的位置来证明(因此,内核不知道它们似乎不是一个问题)。和ls -l /dev/disk/by-partlabel列出b的第一列-所以它似乎不是,他们不被认为是块设备。

我遇到Cyrus提到的问题了吗?(我找不到任何其他似乎暗示了原因)。


就其价值而言……
DMESG报告一些错误

[ 7064.170224] pcieport 0000:00:1c.0: AER: Corrected error received: 0000:00:1c.0
[ 7064.170242] pcieport 0000:00:1c.0: PCIe Bus Error: severity=Corrected, type=Physical Layer, (Receiver ID)
[ 7064.170247] pcieport 0000:00:1c.0:   device [8086:a115] error status/mask=00000001/00002000
[ 7064.170254] pcieport 0000:00:1c.0:    [ 0] RxErr                  (First)
...
[11372.230786] 000-000-1-1-00000-000001: Can't open blockdev
[11372.232977] 000-000-2-1-00000-000001: Can't open blockdev
[11372.235242] 000-000-3-1-00000-000001: Can't open blockdev


在最后的"完成"之后,我试着添加
export "$n"

结果

export: '000-000-3-1-00000-000001': not a valid identifier

更改PARTLABEL以删除'-'符号导致

export: '0000003100000000001: not a valid identifier

所以,除非我的导出是错误的,否则也不是这些。

改成

export N="$n"
and
export "N=$n"

这次没有错误,但是回显$N返回一个空输出。

[SOLUTION]

#! /bin/bash
target_ORG=$(ls '/usr/local/etc/ini/system/ORG')
target_DOMAIN=$(ls '/usr/local/etc/ini/system/DOMAIN')
target_SITE=$(ls '/usr/local/etc/ini/system/SITE')
target_DEVICE=$(ls '/usr/local/etc/ini/system/DEVICE')
target_VOLUME=$(ls '/usr/local/etc/ini/system/VOLUME')
target_HOST=$(ls '/usr/local/etc/ini/system/HOST')

instanceList=$(ls '/dev/disk/by-partlabel')

for i in {1..3} ; do
for n in $instanceList ; do
instance_ORG=${n:0:3}
instance_DOMAIN=${n:4:3}
instance_SAN=${n:8:1}
instance_SITE=${n:10:1}
instance_DEVICE=${n:12:5}
instance_VOLUME=${n:18:6}
mountpoint -q /path/to/$i || mount /dev/disk/by-partlabel/$instance_ORG-$instance_DOMAIN-$i-$instance_SITE-$instance_DEVICE-$instance_VOLUME /path/to/$i >/dev/null 2>&1
done
done

要从可用设备中指定一个特定的子集,在mount命令

中将$instance_*替换为$target_*

我对需求的理解是:

  • 系统在'/dev/disk/by-partlabel'下有设备条目。
  • 每个设备关联一个SAN。
  • 对于每个唯一的SAN,挂载一个(且只有一个)与其关联的设备。

有几种方法可以这样做。一个(Shellcheck-clean)的可能性是:

#! /bin/bash -p
for san in 1 2 3 ; do
for devpath in /dev/disk/by-partlabel/*-*-"$san"-*-*-*; do
mount "$devpath" "/path/to/$san"
break
done
done
  • 无条件中断意味着for devpath in ...循环将在挂载一个与$san当前值相关的设备后停止。总体效果是为每个SAN安装一个设备。

另一个(也是Shellcheck-clean)的方法是:

#! /bin/bash -p
is_mounted_san=()
for devpath in /dev/disk/by-partlabel/*-*-*-*-*-*; do
IFS=- read -r _ _ san _ _ _ <<<"${devpath##*/}"
(( ${is_mounted_san[san]-0} )) && continue
mount "$devpath" "/path/to/$san"
is_mounted_san[san]=1
done
  • 这使用is_mounted_san数组来跟踪哪些san已经挂载了关联的设备。
  • 参见BashFAQ/001(如何逐行(和/或逐字段)读取文件(数据流,变量)?)了解IFS=- read -r _ _ san ...的解释。
  • 参见Bash参考手册中的Here Strings部分,了解... <<<...的解释。
  • 参见移除字符串的一部分(BashFAQ/100(如何在bash中进行字符串操作?))来了解${devpath##*/}的解释。(它删除$devpath中直到并包括最后一个/字符的所有内容。)

相关内容