0

I have created an array:

declare -A months=( ["JAN"]="AP01" ["FEB"]="AP02" ["MAR"]="AP03" ["APR"]="AP04" ["MAY"]="AP05" ["JUN"]="AP06" ["JUL"]="AP07" ["AUG"]="AP08" ["SEP"]="AP09" ["OCT"]="AP10" ["NOV"]="AP11" ["DEC"]="AP12")

Now I want read the replaced value of the month as it splits the file and creates new file name:

awk -F, '{print "a~ST_SAP_FILE~Actual~",echo ${months["${"$3":0:3}"]}","~RM.txt"}' ExtractOriginal.txt

The field where the variable substitution occurs is column 3. In there I have MAR-2016, what I am expecting is a file named: a~ST_SAP_FILE~Actual~MAR~RM.txt. However, I get an error:

awk: syntax error near line 1
awk: illegal statement near line 1
awk: syntax error near line 1
awk: bailing out near line 1

What is the right syntax to take column 3, pass it to my array, return the Substitution variable and use it as the file name?

2
  • 1
    You are using old, broken awk (/bin/awk on Solaris). On Solaris use /usr/xpg4/bin/awk. Commented Sep 19, 2016 at 20:11
  • Possible duplicate of Use array variable in awk? Commented Sep 19, 2016 at 20:16

1 Answer 1

0

There's a few ways you could go about solving your problem. Which you choose is mostly contingent on how tied to awk you want to be.

Declare the array in awk:

Is there any reason for you not to declare the variable in awk?

awk -F, 'BEGIN{months["JAN"]="AP01"; months["FEB"]="AP02"; months["MAR"]="AP03"; months["APR"]="AP04"; months["MAY"]="AP05"; months["JUN"]="AP06"; months["JUL"]="AP07"; months["AUG"]="AP08"; months["SEP"]="AP09"; months["OCT"]="AP10"; months["NOV"]="AP11"; months["DEC"]="AP12"}{print "a~ST_SAP_FILE~Actual~"months[substr($3,0,3)]"~RM.txt"}' ExtractOriginal.txt

(also note that I removed the commas from print, since those will add spaces that your question seems to indicate you do not want in the result)

As @Ed Morton pointed out, due to the nature of your array, we can simplify it's creation with split/sprintf, giving you this:

awk -F, 'BEGIN{split("JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC",t," "); for (i in t) months[t[i]]=sprintf("AP%02d",i)}{print "a~ST_SAP_FILE~Actual~"months[substr($3,0,3)]"~RM.txt"}' ExtractOriginal.txt

Parse the variable into awk:

This seems closest to what you were trying to do in your attempt. This keeps the array available in bash, but handles getting the filename you want with awk. Since there is no native way to handle a bash array in awk, you have to construct the latter from the former (which is made more difficult by this being an associative array).

I did this by first changing the bash array into a more easily parsed string which I then passed into awk as a variable.

# Declare the array
declare -A months=( ["JAN"]="AP01" ["FEB"]="AP02" ["MAR"]="AP03" ["APR"]="AP04" ["MAY"]="AP05" ["JUN"]="AP06" ["JUL"]="AP07" ["AUG"]="AP08" ["SEP"]="AP09" ["OCT"]="AP10" ["NOV"]="AP11" ["DEC"]="AP12")

# Change the array into a string more easily parsed with awk
# Each element in this array is of the format MON=APON
mon=`for key in ${!months[@]}; do echo ${key}'='${months[${key}]}; done`

# See below explanation
awk -F, -v mon="$mon" 'BEGIN {split(mon,tmp," "); for(m in tmp){i = index(tmp[m], "="); months[substr(tmp[m], 1, i-1)] = substr(tmp[m], i+1)}} {print "a~ST_SAP_FILE~Actual~"months[substr($3,0,3)]"~RM.txt"}' ExtractOriginal.txt

Below is a more readable version of the awk script. Note that -v mon="$mon" passes the bash variable mon into awk as a variable also named mon:

 BEGIN {
  split(mon,tmp," ");            # split the string mon into an array named tmp
  for(m in tmp) {                # for element in tmp
    i = index(tmp[m], "=");      # get the index of the '='
    months[substr(tmp[m], 1, i-1)] = substr(tmp[m], i+1)                           
                      # split the elements of tmp at the '='
                      # and add them into an associative array called months
                      # the value is the part which follows the '='
    } 
} 
{
  print "a~ST_SAP_FILE~Actual~"months[substr($3,0,3)]"~RM.txt"
}

Skip awk entirely:

Another option is to simply not use awk at all, which removes the burden of getting the array into a workable state. It's not clear by your question if this is a potential solution for you, but personally I found this bash version much simpler to write/read/understand.

#!/usr/bin/env bash

filename="ExtractOriginal.txt"

declare -A months=( ["JAN"]="AP01" ["FEB"]="AP02" ["MAR"]="AP03" ["APR"]="AP04" ["MAY"]="AP05" ["JUN"]="AP06" ["JUL"]="AP07" ["AUG"]="AP08" ["SEP"]="AP09" ["OCT"]="AP10" ["NOV"]="AP11" ["DEC"]="AP12")

while read line; do                              # for line in file
    month_yr=`echo $line | cut -d',' -f3`        # get the third column
    month=${months[${month_yr:0:3}]}             # get first 3 characters
    echo 'a~ST_SAP_FILE~Actual~'$month'~RM.txt'
done <"$filename"
Sign up to request clarification or add additional context in comments.

5 Comments

Instead of months["JAN"]="AP01"; months["FEB"]="AP02"; months["MAR"]="AP03" you can do split("JAN FEB MAR",t); for (i in t) months[t[i]]=sprintf("AP%02d",i) to make specifying the month to value mapping a bit less tedious and error-prone (e.g.mis-spelling "months" in an assignment).
@SnoringFrog This is pretty awesome, so I got the naming convention to work with your answer, I failed to mentioned that I had to split the file in multiple instances based on that same column 3 ,which contains for example MAR-15 in different rows I want all MAR-15 in the same file not multiple files. Thank you for your help, as I get used to this I hope to get better not only at coding but at asking questions.
My new code looks like this: <i> awk -F, 'BEGIN{months["JAN"]="AP01"; months["FEB"]="AP02"; months["MAR"]="AP03"; months["APR"]="AP04"; months["MAY"]="AP05"; months["JUN"]="AP06"; months["JUL"]="AP07"; months["AUG"]="AP08"; months["SEP"]="AP09"; months["OCT"]="AP10"; months["NOV"]="AP11"; months["DEC"]="AP12"}{print > $3 "a~ST_SAP_FILE_Actual~"months[substr($3,0,3)]"-20" substr($3,5,2)"~RM.txt"}' ExtractOriginal.txt<i> This however appends the Field 3 Name to the file.
@RaulR It's unclear what content you are trying to get into what file.
ok, So I just realized my mistake. I had to keep the Print command and the greater sign before the string. Once again Thank you very much @SnoringFrog

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.