我想:
- 遍历list;
- 查找第一个匹配子字符串的实例;
- 做点什么;
- 忽略任何后续匹配。
- 继续到列表末尾。
更具体:
#! /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
地点:
可用的特定设备随时间而变化
partlabel格式为:xxx-xxx-x- xxx-xxxxxx(例如001-001-1-1-00001-000001),表示该磁盘分区为ORG-DOMAIN-SAN-SITE-DEVICE-VOLUME
/usr/local/etc/ini/system/*目录每个都包含一个以相应子字符串命名的文件-允许通过简单地重命名(而不是必须操作内容)文件
进行更改/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
中直到并包括最后一个/
字符的所有内容。)