【问题标题】:File Name based on Array基于数组的文件名
【发布时间】:2017-01-27 14:27:18
【问题描述】:

我已经创建了一个数组:

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")

现在我想在拆分文件并创建新文件名时读取月份的替换值:

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

变量替换发生的字段是第 3 列。在那里我有MAR-2016,我期待的是一个名为:a~ST_SAP_FILE~Actual~MAR~RM.txt 的文件。但是,我收到一个错误:

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

获取第 3 列的正确语法是什么,将其传递给我的数组,返回 Substitution 变量并将其用作文件名?

【问题讨论】:

  • 您正在使用旧的、损坏的 awk(Solaris 上的 /bin/awk)。在 Solaris 上使用 /usr/xpg4/bin/awk。

标签: arrays variables unix awk


【解决方案1】:

有几种方法可以解决您的问题。你选择哪一个主要取决于你想成为的awk

awk中声明数组:

你有什么理由不在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

(另请注意,我从 print 中删除了逗号,因为这些会添加您的问题似乎表明您不希望在结果中出现的空格)

正如@Ed Morton 所指出的,由于您的数组的性质,我们可以使用split/sprintf 简化它的创建,为您提供:

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

将变量解析成awk:

这似乎最接近您在尝试中尝试做的事情。这使数组在bash 中可用,但使用awk 处理获取您想要的文件名。由于在awk 中没有处理bash 数组的本地方法,因此您必须从前者构造后者(因为这是一个关联数组,这使这变得更加困难)。

我首先将bash 数组更改为更容易解析的字符串,然后将其作为变量传递给awk

# 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

下面是更易读的awk 脚本版本。请注意,-v mon="$mon"bash 变量mon 作为变量传递给awk,也称为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"
}

完全跳过awk

另一种选择是根本不使用awk,这样可以消除使数组进入可用状态的负担。您的问题不清楚这是否是您的潜在解决方案,但我个人发现这个bash 版本更易于编写/阅读/理解。

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

【讨论】:

  • 您可以使用split("JAN FEB MAR",t); for (i in t) months[t[i]]=sprintf("AP%02d",i) 代替months["JAN"]="AP01"; months["FEB"]="AP02"; months["MAR"]="AP03",以使指定月份到值的映射不那么繁琐和容易出错(例如,在作业中拼写错误的“月份”)。跨度>
  • @SnoringFrog 这太棒了,所以我得到了与您的答案一起使用的命名约定,我没有提到我必须根据同一列 3 将文件拆分为多个实例,其中包含例如不同行中的 MAR-15 我希望所有 MAR-15 都在同一个文件中,而不是多个文件中。感谢您的帮助,因为我已经习惯了,我希望不仅在编码方面而且在提问方面都做得更好。
  • 我的新代码如下所示: awk -F, 'BEGIN{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"}{print > $3 "a~ST_SAP_FILE_Actual~"months[substr($3,0,3)]"-20" substr($3,5,2)"~RM.txt" }' ExtractOriginal.txt 但是,这会将字段 3 名称附加到文件中。
  • @RaulR 目前还不清楚您试图将哪些内容放入哪个文件中。
  • 好的,所以我才意识到我的错误。我必须在字符串之前保留 Print 命令和更大的符号。再次非常感谢@SnoringFrog
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 2020-11-17
  • 1970-01-01
  • 2018-10-16
相关资源
最近更新 更多