让我们想象一下,在 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" ]
}