Arrays bash字符串数组

Arrays bash字符串数组,arrays,bash,hash,Arrays,Bash,Hash,我有一个复杂的脚本,它必须根据运行的位置使用不同的代码位 动态地确定这一点没有什么好办法,相反,它必须硬编码并在执行时查找 我想我需要的是这样的东西 { "location": { "type1": [ "hostname1", "hostname2", "hostname 3" ], "type2": [ "hostname4, "hostname5", "hostname6"], "type3": [ "hostname7, "hostname8", "hostname9

我有一个复杂的脚本,它必须根据运行的位置使用不同的代码位

动态地确定这一点没有什么好办法,相反,它必须硬编码并在执行时查找

我想我需要的是这样的东西

{
 "location": {
   "type1": [ "hostname1", "hostname2", "hostname 3" ],
   "type2": [ "hostname4, "hostname5", "hostname6"],
   "type3": [ "hostname7, "hostname8", "hostname9"]
  }
}

case $array[$(hostname)] in #pseudocode 
  type1) bash $dir/type1.sh;;
  type2) bash $dir/type2.sh;;
  *) bash $dir/type3.sh;;
esac
然后,我可以通过某种方式查询以找到其值包含脚本执行器主机名值的键

在ruby中,这就像创建散列并查找值一样简单。 这在bash中可能吗

hash.key(Socket.gethostname)

无论如何,它将被硬编码到脚本中,简单地考虑使用<代码> CASE < /代码>:

case $(hostname) in
  (hostname1|hostname2|hostname3) bash "$dir/type1.sh";;
  (hostname4|hostname5|hostname6) bash "$dir/type2.sh";;
  (*) bash "$dir/type3.sh";;
esac

可以在bash中存储字符串数组,也可以在bash中存储映射,但不能将数组作为值存储在映射中

但是,如果您的类型名仅使用shell变量名中有效的字符,则可以通过将每个数组存储在单独的变量中,并使用间接引用查找或迭代变量名来进行欺骗

#!/bin/bash

[[ $BASH_VERSION ]] && ! [[ $BASH_VERSION =~ ^([0123][.]|4[.][012]) ]] || {
  echo "This requires bash 4.3 or later" >&2
  exit 1
}

# we're declaring any variable name starting with loc_ to be part of our data
loc_type1=( "hostname1" "hostname2" "hostname3" )
loc_type2=( "hostname4" "hostname5" "hostname6" )
loc_type3=( etc etc etc )

# map from type to hostnames; "hosts_for_type type1" will emit hostnames 1-3
hosts_for_type() {
  local -n type_arr="loc_$1"
  printf '%s\n' "${type_arr[@]}"
}

# do the heavy lifting to build a map from hostnames to types
# this only needs to be run once for the given data
declare -g -A type_for_host=( )
build_hosttype_map() {
  local varname typename host

  # abort if inverse map is already built so this only runs once
  (( ${#type_for_host[@]} )) && return

  for varname in "${!loc_@}"; do
    declare -n locarr="$varname"
    typename=${varname#loc_}
    for host in "${locarr[@]}"; do
      type_for_host[$host]=$typename
    done
  done
}

# map from hostname to type; uses inverse map built above.
type_for_host() {
  build_hosttype_map
  printf '%s\n' "${type_for_host[$1]}"
}
根据上述定义:

$ type_for_host hostname1
type1
$ hosts_for_type type1
hostname1
hostname2
hostname3

(如果您想处理包含所有可能字符的数据元素,您需要将
'%s\n'
格式字符串更改为
'%s\0'
,从换行分隔符切换为NUL;但是,由于我们的输入域目前仅由有效主机名组成,因此不会立即调用)。

Waitaminute。您是按主机还是按类型进行查找?您的伪代码表示前者,但您的字典是为后者创建的。您知道这更聪明、更简单。感谢您指出。如果您修复了引号,您将有一个很好的解决方案,正如另一个答案下面的注释所指出的。修复了引号和间距/缩进;感谢大卫和查尔斯指出这一点!哦,天哪,这比我想象中的巴什还要难看。我真的很感激你在这方面所做的努力。语法上的丑陋和概念上的丑陋之间有很大的区别——这里有很多语法,但它是定义良好的语法,无论运行时环境、数据等如何,都将以一致的方式运行(当然,除了用
loc
前缀划出我们保留的变量名称空间)。这与$(find…)中文件的
之类的东西相比,这些东西看起来并不可怕,但实际上它们在运行时所做的事情充满了极端情况和丑陋。即使是公认的答案,尽管简短,也有一些地方有另一个更微妙的地方(我认为更严肃)有点难看:
$dir/type1.sh
如果目录名中有空格,或者
IFS
值包含该名称中的字符(例如
/
),则会以意外的方式运行;它必须是
“$dir”/type1.sh
(或
“$dir/type1.sh”
)才是正确的,没有先决条件或警告。有些人只是喜欢漫画部分而不是莎士比亚。。。虽然引用了更正,但它非常简短,而且切中要害……毫无疑问——另一个(更正后)应该是可接受的答案;它比这更适合OP的即时用例。(如果有人需要动态构建地图,然后高效地进行任意数量的反向查找,那么这个答案很有价值,因此我认为它为这个问题增加了一些价值,但现在它不是OP的最佳选择)。