关联数组数据的棘手处理
Tricky handling of associative array'ish data
我有一个如下所示的配置文件:
#!/bin/bash
# lots of other stuff
declare -A PARTITIONS
PARTITIONS[ROOT,DEV]=/dev/mmcblk0p2
PARTITIONS[ROOT,MNT]=/
PARTITIONS[ROOT,FSTYPE]=ext4
PARTITIONS[ROOT,OPTS]='rw,suid,exec,auto,nouser,async,errors=remount-ro,noatime,nodiratime,commit=120 0 1'
PARTITIONS[ROOT,START]=64MB
PARTITIONS[ROOT,END]=6143.9MB
PARTITIONS[ROOT,OWNER]=root.root
PARTITIONS[ROOT,PERMS]=755
PARTITIONS[DATA,DEV]=/dev/mmcblk0p7
PARTITIONS[DATA,MNT]=/data
PARTITIONS[DATA,FSTYPE]=xfs
PARTITIONS[DATA,OPTS]='rw,noexec,auto,user,suid,noatime,nodiratime,async,logbufs=4,noquota 0 3'
PARTITIONS[DATA,START]=12288MB
PARTITIONS[DATA,END]=-1s
PARTITIONS[DATA,OWNER]=root.root
PARTITIONS[DATA,PERMS]=755
等等等等等等
当我将其包含在配置脚本中并迭代 AA 的密钥时,我没有按特定顺序获取它们。密钥的右侧部分(DEV、MNT...)是固定的,但并非所有都是强制性的,而左侧部分可以是随机的(只是助记符)。
我需要的是左边部分的列表,知道哪些分区必须创建,然后找出右边的哪些部分被定义(如果没有,设置一个默认值),这样每个分区都会很好- 在实际创建分区之前定义,将其添加到 fstab,挂载...
我们在这里谈论的是新系统。完成任务的唯一两个选项是 Bash and/or Perl。没有 JavaScript,没有 Python,没有 C# 脚本,抱歉。 Sed 和 Awk 可用。因为之前的设置步骤是在 Bash 中完成的,所以我更喜欢简单的 Bash(如果需要,加上 Sed/Awk)解决方案。
当然可以更改配置文件。唯一强制性的事情是保持按键左侧部分的灵活性。
awk
救援!
$ awk -F'[\]\[,]' '/^PARTITIONS/{a[]=a[]?a[] OFS :}
END{for(k in a) print k ": " a[k]}' conf
DATA: DEV MNT FSTYPE OPTS START END OWNER PERMS
ROOT: DEV MNT FSTYPE OPTS START END OWNER PERMS
您可以通过设置 OFS 更改正确组件之间的分隔符。
虽然我倾向于同意@EdMorton 的评论,即 awk 是一个优秀的工具,但这个问题并不是特别复杂,bash 可能就好了:
# Find all the left-hand keys
declare -A keys
for key in "${!PARTITIONS[@]}"; do
keys[${key%%,*}]=1
done
# Set defaults and/or check validity
errors=0
for key in "${!keys[@]}"; do
# Set a default
: "${PARTITIONS[$key,FSTYPE]:=ext4}"
# Make sure a setting exists.
# -v requires v4.2; otherwise use -n/-z. Maybe you
# want those anyway, since a blank config might be an error.
if [[ ! -v PARTITIONS[$key,MNT] ]]; then
printf "MNT key missing for partition %s\n" "$key" >>/dev/stderr
# Remove it from the set so it doesn't show up later
unset keys[$key]
((errors++))
fi
# Etc.
done
# For debugging purposes, just print out the settings
for key in "${!keys[@]}"; do
printf "$key:"
for field in DEV MNT FSTYPE OPTS START END OWNER PERMS; do
printf " %s=%b" $field "${PARTITIONS[$key,$field]}"
done
echo
done
if ((errors)); then
printf "Config errors. Not proceeding\n" >> /dev/stderr
return 1
fi
# Do what needs to be done
# probably another loop over keys
我有一个如下所示的配置文件:
#!/bin/bash
# lots of other stuff
declare -A PARTITIONS
PARTITIONS[ROOT,DEV]=/dev/mmcblk0p2
PARTITIONS[ROOT,MNT]=/
PARTITIONS[ROOT,FSTYPE]=ext4
PARTITIONS[ROOT,OPTS]='rw,suid,exec,auto,nouser,async,errors=remount-ro,noatime,nodiratime,commit=120 0 1'
PARTITIONS[ROOT,START]=64MB
PARTITIONS[ROOT,END]=6143.9MB
PARTITIONS[ROOT,OWNER]=root.root
PARTITIONS[ROOT,PERMS]=755
PARTITIONS[DATA,DEV]=/dev/mmcblk0p7
PARTITIONS[DATA,MNT]=/data
PARTITIONS[DATA,FSTYPE]=xfs
PARTITIONS[DATA,OPTS]='rw,noexec,auto,user,suid,noatime,nodiratime,async,logbufs=4,noquota 0 3'
PARTITIONS[DATA,START]=12288MB
PARTITIONS[DATA,END]=-1s
PARTITIONS[DATA,OWNER]=root.root
PARTITIONS[DATA,PERMS]=755
等等等等等等
当我将其包含在配置脚本中并迭代 AA 的密钥时,我没有按特定顺序获取它们。密钥的右侧部分(DEV、MNT...)是固定的,但并非所有都是强制性的,而左侧部分可以是随机的(只是助记符)。
我需要的是左边部分的列表,知道哪些分区必须创建,然后找出右边的哪些部分被定义(如果没有,设置一个默认值),这样每个分区都会很好- 在实际创建分区之前定义,将其添加到 fstab,挂载...
我们在这里谈论的是新系统。完成任务的唯一两个选项是 Bash and/or Perl。没有 JavaScript,没有 Python,没有 C# 脚本,抱歉。 Sed 和 Awk 可用。因为之前的设置步骤是在 Bash 中完成的,所以我更喜欢简单的 Bash(如果需要,加上 Sed/Awk)解决方案。
当然可以更改配置文件。唯一强制性的事情是保持按键左侧部分的灵活性。
awk
救援!
$ awk -F'[\]\[,]' '/^PARTITIONS/{a[]=a[]?a[] OFS :}
END{for(k in a) print k ": " a[k]}' conf
DATA: DEV MNT FSTYPE OPTS START END OWNER PERMS
ROOT: DEV MNT FSTYPE OPTS START END OWNER PERMS
您可以通过设置 OFS 更改正确组件之间的分隔符。
虽然我倾向于同意@EdMorton 的评论,即 awk 是一个优秀的工具,但这个问题并不是特别复杂,bash 可能就好了:
# Find all the left-hand keys
declare -A keys
for key in "${!PARTITIONS[@]}"; do
keys[${key%%,*}]=1
done
# Set defaults and/or check validity
errors=0
for key in "${!keys[@]}"; do
# Set a default
: "${PARTITIONS[$key,FSTYPE]:=ext4}"
# Make sure a setting exists.
# -v requires v4.2; otherwise use -n/-z. Maybe you
# want those anyway, since a blank config might be an error.
if [[ ! -v PARTITIONS[$key,MNT] ]]; then
printf "MNT key missing for partition %s\n" "$key" >>/dev/stderr
# Remove it from the set so it doesn't show up later
unset keys[$key]
((errors++))
fi
# Etc.
done
# For debugging purposes, just print out the settings
for key in "${!keys[@]}"; do
printf "$key:"
for field in DEV MNT FSTYPE OPTS START END OWNER PERMS; do
printf " %s=%b" $field "${PARTITIONS[$key,$field]}"
done
echo
done
if ((errors)); then
printf "Config errors. Not proceeding\n" >> /dev/stderr
return 1
fi
# Do what needs to be done
# probably another loop over keys