使用 sed 替换关联 bash 数组中的匹配值

Use sed to replace matched value from associative bash array

我正在使用 sed 重新格式化输入字符串,我想用不同的字符串替换其中的一部分。

输入的字符串是日期,格式为:

%Y-%m-%dT%H:%M:%S.%N%:z
Example:
2016-01-20T08:15:32.398242-05:00

我的目标是将上面例子中的01替换成字符串表示,例如Jan.

我定义了以下要使用的数组:

declare -A MONTHS=([01]="Jan" [02]="Feb" [03]="Mar" [04]="Apr" [05]="May" [06]="Jun" [07]="Jul" [08]="Aug" [09]="Sep" [10]="Oct" [11]="Nov" [12]="Dec")

我似乎无法 sed 使用匹配组的值作为 MONTHS 数组的索引。

我尝试过的:

# straightforward sed approach
sed 's/^[0-9]\{4\}-\([0-9]\{2\}\)-.*/${MONTHS[]}/g'
# result: ${MONTHS[01]}

# break out of the single quotes
sed 's/^[0-9]\{4\}-\([0-9]\{2\}\)-.*/'"${MONTHS[]}"'/g'
# result: 

# use double quotes
sed "s/^[0-9]\{4\}-\([0-9]\{2\}\)-.*/${MONTHS[]}/g"
# result: 

# use double quotes *and* a hardcoded example
sed "s/^[0-9]\{4\}-\([0-9]\{2\}\)-.*/${MONTHS[]}, ${MONTHS[01]}/g"
# result: , Jan

是否可以使用 sed 中的匹配组值作为替换中的数组索引?

注意: 我有意避免使用 date 函数,因为它的应用可能超出实际日期;但是,我绝对愿意接受其他方法,例如 awk.

首先,您可以将关联数组转换为按顺序包含月份名称的字符串

monstr=$(for k in "${!MONTHS[@]}"; do echo $k; done | sort | while read mon; do echo ${MONTHS[$mon]}; done)

然后,使用awk来完成繁重的工作

awk -F- -v monstr="$monstr" 'BEGIN { split(monstr, mon, " "); } { printf("%s-%s-", , mon[+0]); for (i=3; i < NF; i++) { printf("%s-", $i); } printf("%s\n", $NF);}'

也就是把包含月份的字符串存入你一开始拆分的变量中,然后替换第二个字段打印所有。

我建议 awk 作为替代方案:

s='2016-01-20T08:15:32.398242-05:00'

awk -v ms='Jan:Feb:Mar:Apr:May:Jun:Jul:Aug:Sep:Oct:Nov:Dec' 'BEGIN{
   split(ms, mths, ":"); FS=OFS="-"} {=mths[+0]} 1' <<< "$s"

输出:

2016-Jan-20T08:15:32.398242-05:00

首先从您的数组生成 sed 脚本,然后执行它。

免责声明:不确定我在以下代码中是否正确使用了 bash 数组。也不确定引号和转义。

for k in $(seq -w 1 12) ; do
    echo 's/^[0-9]\{4\}-'"$k-.*/${MONTHS[$k]}/;"
done | sed -f - your_file

或者只使用 bash:

IFS=- read year mon rest <<<"$string"
string="$year ${MONTHS[$mon]} $rest"

如果必须 sed...这是使用 t 命令的 "brute force" 答案:

#! /bin/sed -f
s/-01-/-Jan-/; tx
s/-02-/-Feb-/; tx
s/-03-/-Mar-/; tx
s/-04-/-Apr-/; tx
s/-05-/-May-/; tx
s/-06-/-Jun-/; tx
s/-07-/-Jul-/; tx
s/-08-/-Aug-/; tx
s/-09-/-Sep-/; tx
s/-10-/-Oct-/; tx
s/-11-/-Nov-/; tx
s/-12-/-Dec-/; tx
:x