输出

输出

让我们想象一下,在 bash 脚本的中间,我有一个像这样的字符串数组:

example1.log    
example1.log.1
log2.log
xpto.log
xpto.log.1
xpto.log.2

有没有办法将它变成一个包含这样格式的字符串的关联数组(所需数组结构的表示):

{
    "example1" : [ "example1.log", "example1.log.1" ],
    "log2" : [ "log2.log" ],
    "xpto" : [ "xpto.log", "xpto.log.1", "xpto.log.2" ]
}

笔记:

  • 初始字符串始终具有类似non-predictable-name+ .log+ 的格式.x(可选点和整数)

谢谢。

答案1

这是一个解决方案bash(版本> = 4):

declare -A logs
for logfile in *; do
    logs[${logfile%%.*}]+="$logfile "
done

作为使用关联数组的示例,您可以像这样打印它:

for log in "${!logs[@]}"; do
    echo "$log:"
    for file in ${logs[$log]}; do
        echo "- $file"
    done
done

(我假设您的日志文件名称中都没有空格)

答案2

尽管bash关联数组的灵感来自ksh93's 数组(尽管有其缺点),但它不支持将除标量以外的任何值分配给其值。

对于值可以是数组的关联数组,您需要ksh93

$ ksh -c 'typeset -A logs; for f in *.log*; do logs[${f%.log*}]+=($f); done; typeset -p logs'
typeset -A logs=([example1]=(example1.log example1.log.1) [log2]=(log2.log) [xpto]=(xpto.log xpto.log.1 xpto.log.2) )

要循环它们:

typeset -A logs
for f in *.log*; do logs[${f%.log*}]+=($f); done

for key in "${!logs[@]}"; do
  printf '%s:\n' "$key"
  for file in "${logs[$key][@]}"; do
     printf ' File: "%s"\n' "$file"
  done
done

zsh关联数组也只能有标量值,但由于这些值可能包含 NUL 字符,因此它们可以存储任意文件名的列表(通过用 NUL 字符分隔它们)。用bash,这里由于文件名都在当前目录下,所以可以用 . 分隔/。或者,如果您可以假设文件名中没有出现特定字符(例如 @xhienne 使用空格字符的方法),则可以使用它。另请注意,bash关联数组具有键不能为空的限制。

答案3

cat - <<\eof |
example1.log
example1.log.1
log2.log
xpto.log
xpto.log.1
xpto.log.2
eof
perl -lne '

/(.*)\.log(?=\.\d+$|$)/ and
   push(@{$h{$1}}, qq/"$_"/), $h[-1+keys %h]=$1;

END{

   print for 
      q/{/,

      join(",\n",
         map {
            join($",
               qq/\t"$_"/,
               q/:/,
               q/[/,
               join(", ", @{$h{$_}}),
               q/]/,
            )
         } @h
      ),

      q/}/

}
'

输出

{
   "example1" : [ "example1.log", "example1.log.1" ],
   "log2" : [ "log2.log" ],
   "xpto" : [ "xpto.log", "xpto.log.1", "xpto.log.2" ]
}

相关内容