【问题标题】:Tricky handling of associative array'ish data关联数组数据的棘手处理
【发布时间】:2016-05-07 08:31:02
【问题描述】:

我有一个如下所示的配置文件:

#!/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 和/或 Perl。没有 JavaScript,没有 Python,没有 C# 脚本,抱歉。可以使用 Sed 和 Awk。因为之前的设置步骤是在 Bash 中完成的,所以我更喜欢普通的 Bash(加上 Sed/Awk,如果需要)解决方案。

当然可以更改配置文件。唯一必须做的就是保持键左侧部分的灵活性。

【问题讨论】:

  • 我还是不太明白你在做什么?
  • iterate the keys of the AA 是什么意思?在给定输入的情况下发布预期的输出。正确的解决方案将在 awk 中,顺便说一句 - 唯一的 bash 部分将在它调用 awk 时。 shell 是从中调用工具的环境,而不是操作文本的工具,所有 UNIX 系统上的标准通用文本操作工具是 awk。
  • 如果需要丰富的数据结构,不要使用bash
  • 默认值是固定的,还是您需要知道该键的其他一些配置才能计算默认值?
  • @123:此文件(或类似文件)是一组脚本的一部分,用于在 Raspberry Pis 上自动设置某种 Linux(“MiniBian”)。此分布的默认分区非常小。因为并非所有 Pi 都这样做,所以必须具有配置文件的灵活性来控制脚本的行为。 @EdMorton:在更复杂的编码语言中,你会这样写:var aa = new Dictionary<string, string>();foreach (var key in aa.Keys) {// Do some fancy stuff with the keys}@rici:是固定的。

标签: arrays bash awk sed associative


【解决方案1】:

虽然我倾向于同意 @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

【讨论】:

  • 虽然我同意你关于 Ed 的回答和他的建议,即在像我这样的情况下,Awk 将成为首选工具,但我最好坚持使用我可以阅读的脚本语言,比如 Bash脚本...至少在阅读了 karakfa 的建议和 Ed 对此的评论之后,并且这样做时感觉就像一只盯着发条的猴子 ^^(对我自己的注意:阅读一本好的 Awk 入门书!)谢谢,rici!
  • PS:效果非常好,rici!你救了我的一天! ^^
【解决方案2】:

awk 来救援!

$ awk -F'[\\]\\[,]' '/^PARTITIONS/{a[$2]=a[$2]?a[$2] OFS $3:$3}
                               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 来更改正确组件之间的分隔符。

【讨论】:

  • 因为我之前已经告诉过你很多次关于这些问题并且它不会改变你编码的方式我不会在这段时间之后再次提出它们:你需要测试$2 in a , 而不是a[$2] 或者当a[$2] 计算结果为零或空时条件将失败,并且您需要将三元表达式括起来,否则它们会在某些 awk 中的某些上下文中导致语法错误(并且将它们括起来会使代码更具可读性) ) 并且您不应多次重复指定相同的值。所以你应该使用a[$2]=($2 in a?a[$2] OFS:"") $3 而不是a[$2]=a[$2]?a[$2] OFS $3:$3
  • 我绝对应该将 Awk 添加到我的 To-Learn-List 中。这似乎比 Perl 中的解决方案更危险^^
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多