Reputation: 38456
I'm using sed
to reformat an input string, a portion of which I want replaced with a different string.
The input string is a date in the format of:
%Y-%m-%dT%H:%M:%S.%N%:z
Example:
2016-01-20T08:15:32.398242-05:00
My goal is to replace the month, 01
in the example above, with a string representation such as Jan
.
I've defined the following array to use:
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")
I can't seem to get sed
to use a matched group's value as the index to the MONTHS
array.
What I've tried:
# 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
Is it possible to use a matched-group value from sed
as an array index in the replacement?
Note: I'm purposefully avoiding the date
function because the application of this can go beyond actual dates; but, I'm definitely open to alternative approaches such as awk
.
Upvotes: 3
Views: 2031
Reputation: 1871
If it must be sed... Here is a "brute force" answer using the t command:
#! /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
Upvotes: 0
Reputation: 17858
First generate sed
script from your array, then execute it.
Disclaimer: not sure that I correctly used bash array in the following code. Also not sure about quotes and escaping.
for k in $(seq -w 1 12) ; do
echo 's/^[0-9]\{4\}-'"$k-.*/${MONTHS[$k]}/;"
done | sed -f - your_file
Alternatively just use bash
:
IFS=- read year mon rest <<<"$string"
string="$year ${MONTHS[$mon]} $rest"
Upvotes: 1
Reputation: 785631
I suggest this awk
as an alternative:
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"
Output:
2016-Jan-20T08:15:32.398242-05:00
Upvotes: 1
Reputation: 69358
First, you can convert your associative array to a string containing the months names in order
monstr=$(for k in "${!MONTHS[@]}"; do echo $k; done | sort | while read mon; do echo ${MONTHS[$mon]}; done)
then, use awk
to do the heavy lifting
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);}'
That is, store the string containing the months in a varaible that you split at the beginning, then replace the second field and print all.
Upvotes: 1