linux - 动态间接 Bash 数组

标签 linux bash shell unix

我有这种格式的日志:

log1,john,time,etc
log2,peter,time,etc
log3,jack,time,etc
log4,peter,time,etc

我想为格式中的每个人创建一个列表

"name"=("no.lines" "line" "line" ...)

例如:

peter=("2" "log2,peter,time,etc" "log4,peter,time,etc")

我已经有了这个结构并且知道如何创建像这样的变量

declare "${FIELD[1]}"=1

但我不知道如何增加记录的数量,如果我想创建这样的列表并将其附加到其中,我会收到错误消息。

#!/bin/bash

F=("log1,john,time,etc" "log2,peter,time,etc" "log3,jack,time,etc" "log4,peter,time,etc")
echo "${F[@]}"

declare -a CLIENTS
for LINE in "${F[@]}"
do
    echo "$LINE"
    IFS=',' read -ra  FIELD < <(echo "$LINE")

    if [ -z "${!FIELD[1]}" ] && [ -n "${FIELD[1]}" ] # check if there is already record for given line, if not create
    then 
            CLIENTS=("${CLIENTS[@]}" "${FIELD[1]}") # add person to list of variables records for later access
            declare -a "${FIELD[1]}"=("1" "LINE") # ERROR

    elif [ -n "${!FIELD[1]}" ] && [ -n "${FIELD[1]}" ] # if already record for client
    then 
            echo "Increase records number" # ???
            echo "Append record"
            "${FIELD[@]}"=("${FIELD[@]}" "$LINE") # ERROR

    else    
            echo "ELSE"
    fi

done

echo -e "CLIENTS: \n ${CLIENTS[@]}"
echo "Client ${CLIENTS[0]} has ${!CLIENTS[0]} records"
echo "Client ${CLIENTS[1]} has ${!CLIENTS[1]} records"
echo "Client ${CLIENTS[2]} has ${!CLIENTS[2]} records"
echo "Client ${CLIENTS[3]} has ${!CLIENTS[3]} records"

最佳答案

注意:下面使用了 namevars,一个新的 bash 4.3 特性。


首先:我强烈建议使用前缀命名数组以避免与无关变量发生冲突。因此,使用 content_ 作为前缀:

read_arrays() {
  while IFS= read -r line && IFS=, read -r -a fields <<<"$line"; do
    name=${fields[1]}
    declare -g -a "content_${fields[1]}"
    declare -n cur_array="content_${fields[1]}"
    cur_array+=( "$line" )
    unset -n cur_array
  done
}

然后:

lines_for() {
  declare -n cur_array="content_$1"
  printf '%s\n' "${#cur_array[@]}" ## emit length of array for given person
}

……或者……

for_each_line() {
  declare -n cur_array="content_$1"; shift
  for line in "${cur_array[@]}"; do
    "$@" "$line"
  done
}

将所有这些结合在一起:

$ read_arrays <<'EOF'
log1,john,time,etc
log2,peter,time,etc
log3,jack,time,etc
log4,peter,time,etc
EOF
$ lines_for peter
2
$ for_each_line peter echo
log2,peter,time,etc
log4,peter,time,etc

...并且,如果您真的想要您要求的格式,将列数作为显式数据,并且变量名没有安全命名空间,则很容易从一个格式转换对另一个:

# this should probably be run in a subshell to avoid namespace pollution
# thus, (generate_stupid_format) >output
generate_stupid_format() {
  for scoped_varname in "${!content_@}"; do
    unscoped_varname="${scoped_varname#content_}"
    declare -n unscoped_var=$unscoped_varname
    declare -n scoped_var=$scoped_varname
    unscoped_var=( "${#scoped_var[@]}" "${scoped_var[@]}" )
    declare -p "$unscoped_varname"
  done
}

关于linux - 动态间接 Bash 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35607135/

相关文章:

linux - 搜索文本

linux - 如何找到行和单词的总和

linux - 拥有一个包含同名不同文件的文件夹

mysql - 在没有用户的情况下恢复mysql备份

linux - 如何提高更改文件和文件夹权限的性能?

bash - 从 Amazon S3 存储桶下载文件的脚本

linux - 面对shell脚本中的文件夹路径问题

regex - sed 编辑文件中的一行

linux - Bash 脚本将工作目录更改为它所在的目录

通过脚本修改linux跨发行版环境变量?