问题描述
我正在尝试编写一个备份脚本,该脚本采用磁盘UUID的特定列表,将它们挂载到指定的点,rsync
将数据保存到指定的端点,然后还执行其他一系列条件操作检查何时完成。但是,由于在rsync
之后会进行大量检查,因此最好将每个磁盘的UUID和关联/所需的挂载点设置为字符串,以在整个脚本中保存对它们的硬编码,以及是否说UUID将来会更改(如果驱动器已更新或换出),则可以更轻松地维护脚本...
我一直在查看bash中的数组,以列出所需的磁盘,但是由于我对数组的经验不存在,因此对如何实现此目的有疑问!
磁盘列表-要备份的优先级顺序-是:
# sdc1 2.7T UUID 8C1CC0C19D012E29 /media/user/Documents/
# sdb1 1.8T UUID 39CD106C6FDA5907 /media/user/Photos/
# sdd1 3.7T UUID 5104D5B708E102C0 /media/user/Video/
...,请注意,我要输入sd c 1,sd b 1,sd d 1,依此类推(即自定义订单)。
是否可以按照优先级顺序创建此列表,所以就像这样?
disksToBackup
└─1
└─UUID => '8C1CC0C19D012E29'
└─MountPoint => '/media/user/Documents/'
└─2
└─UUID => '39CD106C6FDA5907'
└─MountPoint => '/media/user/Photos/'
└─3
└─UUID => '5104D5B708E102C0'
└─MountPoint => '/media/user/Video/'
或者比这更好的主意...
然后如何实际使用呢?
例如,假设如何遍历列表并装入每个磁盘(我知道这是不正确的语法,但我对数组一无所知:
mount --uuid $disksToBackup[*][UUID] $disksToBackup[*][MountPoint]
?
更新:使用Linux Mint 19.3
bash --version
的输出给出:GNU bash,version 4.4.20(1)
解决方法
作为一个如何将这些数据读入一系列数组的示例:
#!/usr/bin/env bash
i=0
declare -g -A "disk$i"
declare -n currDisk="disk$i"
while IFS= read -r line || (( ${#currDisk[@]} )); do : "line=$line"
if [[ $line ]]; then
if [[ $line = *=* ]]; then
currDisk[${line%%=*}]=${line#*=}
else
printf 'WARNING: Ignoring unrecognized line: %q\n' "$line" >&2
fi
else
if [[ ${#currDisk[@]} ]]; then
declare -p "disk$i" >&2 # for debugging/demo: print out what we created
(( ++i ))
unset -n currDisk
declare -g -A "disk$i=( )"
declare -n currDisk="disk$i"
fi
fi
done < <(blkid -o export)
这给你类似的东西
declare -g -A disk0=( [PARTLABEL]="primary" [UUID]="1111-2222-3333" [TYPE]=btrfs ...)
declare -g -A disk1=( [PARTLABEL]="esp" [LABEL]="boot" [TYPE]="vfat" ...)
...这样您就可以编写代码遍历它们,进行所需的任何搜索/比较/等操作。例如:
for _diskVar in "${!disk@}"; do # iterates over variable names starting with "disk"
declare -n _currDisk="$_diskVar" # refer to each such variable as _currDisk in turn
# replace the below with your actual application logic,whatever that is
if [[ ${_currDisk[LABEL]} = "something" ]] && [[ ${_currDisk[TYPE]} = "something_else" ]]; then
echo "Found ${_currDisk[DEVNAME]}"
fi
unset -n _currDisk # clear the nameref when done with it
done
,
从版本4开始的Bash提供了关联数组,但仅使用单个维度。您必须使用'sdc1-uuid'之类的键来模拟多个维度,如以下交互式bash示例所示(删除前导@apollo/client/core
和$
并在放入脚本时删除bash输出)。>
>
但是,键没有顺序(键的顺序与我们定义键的顺序不同)。您可能要使用第二个数组,如以下示例所示,它也可以分解多个维度:
$ declare -A disks
$ disks=([0-uuid]=8C1CC0C19D012E29 [0-mount]=/media/user/Documents/
> [1-uuid]=39CD106C6FDA5907 [1-mount]=/media/user/Photos/)
$ echo ${disks[sdc1-uuid]}
8C1CC0C19D012E29
$ echo ${disks[*]}
/media/user/Documents/ 39CD106C6FDA5907 8C1CC0C19D012E29 /media/user/Photos/
$ echo ${!disks[*]}
0-mount 0-uuid 1-uuid 1-mount
如果使用bash版本3,则需要使用其他方法来模拟关联数组。请参阅associative arrays in bash 3上的问题,或简单地以简单的数组表示您的结构,例如,这样一来,所有内容都变得更加可读:
$ disks_order=(0 1)
$ for i in ${disks_order[*]}; do
> echo "${disks[$i-uuid]} ${disks[$i-mount]}"
> done
8C1CC0C19D012E29 /media/user/Documents/
39CD106C6FDA5907 /media/user/Photos/
$ disks=(8C1CC0C19D012E29=/media/user/Documents/
> 39CD106C6FDA5907=/media/user/Photos/)
$ for disk in "${disks[@]}"; do
> uuid="${disk%=*}"
> path="${disk##*=}"
> echo "$uuid $path"
> done
8C1CC0C19D012E29 /media/user/Documents/
39CD106C6FDA5907 /media/user/Photos/
是一种奇妙的说法,表示删除%=*
符号后(包括)后的所有内容。然后=
删除##*=
符号之前(包括)的所有内容。