【问题标题】:Use sed to replace matched value from associative bash array使用 sed 替换关联 bash 数组中的匹配值
【发布时间】:2016-01-20 15:46:45
【问题描述】:

我正在使用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[\1]}/g'
# result: ${MONTHS[01]}

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

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

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

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

注意: 我故意避免使用date 函数,因为它的应用可能超出实际日期;但是,我绝对愿意接受 awk 等替代方法。

【问题讨论】:

    标签: regex bash replace sed associative-array


    【解决方案1】:

    我建议使用 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="-"} {$2=mths[$2+0]} 1' <<< "$s"
    

    输出:

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

    【讨论】:

    • 太棒了,这很好用!我真的很喜欢它让我也可以内联替换值,并且其他所有内容都很容易根据我的需要进行修改。谢谢=]
    【解决方案2】:

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

    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-", $1, mon[$2+0]); for (i=3; i < NF; i++) { printf("%s-", $i); } printf("%s\n", $NF);}'
    

    也就是说,将包含月份的字符串存储在您在开头拆分的变量中,然后替换第二个字段并全部打印。

    【讨论】:

    • 这很好用,谢谢!多个printf() 语句起初使修改有点混乱,但我现在已经掌握了它的窍门,它完全符合我的需要=]
    【解决方案3】:

    首先从您的数组中生成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"
    

    【讨论】:

      【解决方案4】:

      如果必须 sed... 这是使用 t 命令的“蛮力”答案:

      #! /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
      

      【讨论】:

        猜你喜欢
        • 2018-04-27
        • 1970-01-01
        • 2013-06-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多