在unix中获取逗号分隔的不同值
我有一个unix文件Err_Call_sipregtracking.csv,如下所示在unix中获取逗号分隔的不同值,unix,awk,Unix,Awk,我有一个unix文件Err_Call_sipregtracking.csv,如下所示 colnum~filename~date~fieldnum~name~value 15~YYYYMMDD_BDACA_SELFRELATIVE_ARN~30MAR2016:00:00:00~1~BDA_CA_Code~1 15~YYYYMMDD_BDACA_SELFRELATIVE_ARN~30MAR2016:00:00:00~2~ARN_Code~2 15~YYYYMMDD_BDACA_SELFRELATIV
colnum~filename~date~fieldnum~name~value
15~YYYYMMDD_BDACA_SELFRELATIVE_ARN~30MAR2016:00:00:00~1~BDA_CA_Code~1
15~YYYYMMDD_BDACA_SELFRELATIVE_ARN~30MAR2016:00:00:00~2~ARN_Code~2
15~YYYYMMDD_BDACA_SELFRELATIVE_ARN~30MAR2016:00:00:00~544~ALL~0
15~YYYYMMDD_BDACA_SELFRELATIVE_ARN~30MAR2016:00:00:00~544~ALL~0
这里的delimeter是~
。
我希望将name列的不同值放入变量中
我需要的输出是:
'BDA_CA_Code','ARN_Code','ALL'
请帮我做到这一点,我试过了
cat Err_Call_sipregtracking.csv | awk -F'~' '{print $5}' | uniq
输出为:
name
BDA_CA_Code
ARN_Code
ALL
但我不希望结果中出现标题,我还希望它们以引号和逗号分隔。这里的关键是将值存储在数组中,因此您可以打印所有元素:
$ awk -F'~' 'NR>1{item[$5]} END {for (i in item) print i}' file
ARN_Code
BDA_CA_Code
ALL
注意使用NR>1
跳过标题
然后,您可以使用printf“\047%s\047\n”,i
打印用单引号包装的元素,因为print“\047hello\047”
打印'hello'
:
$ awk -F'~' 'NR>1{item[$5]} END {for (i in item) printf "\047%s\047\n", i}' file
'ARN_Code'
'BDA_CA_Code'
'ALL'
要将这些项目连接到以逗号分隔的项目列表中,只需在从第二个项目开始的每个项目之前打印一个逗号():
在行动中看到它:
$ awk -F'~' 'NR>1{item[$5]} END {for (i in item) printf "%s\047%s\047", (++c>1 ? "," : ""), i; print ""}' file
'ARN_Code','BDA_CA_Code','ALL'
这可能不是很优化,但有效:
tail -n+2 Newfile.csv | awk -F'~' '{$5="\""$5"\""; print $5}' | uniq | tr '\n' ',' | sed 's/\,$/\n/'
如果您想要单引号:
tail -n+2 Newfile.csv | awk -F'~' '{a = "'"'"'"; print a $5 a}' | uniq | tr '\n' ',' | sed 's/\,$/\n/'
说明:
省略第一行tail-n+2 Newfile.csv
提取第5列并用引号将其括起来(对于单引号,请注意引号打印是多么的复杂,可能有一种解决方法)awk-F'~'''{$5=“\'$5”\”;print$5}'
删除重复项uniq
用逗号替换换行符tr'\n'','
删除最后一个逗号,并用换行符替换它(为了输出可读性)sed's/\,$/\n/'
awk是你的朋友:
$ var=$(awk -v FS="~" 'NR>1 && !($5 in field){printf "\047%s\047,",$5;field[$5]}' Err_Call_sipregtracking.csv)
$ var="${var%,}" #Stripping the trailing comma
$ echo "$var"
'BDA_CA_Code','ARN_Code','ALL'
注释
- 我使用了octal
作为他在评论中建议的单引号。看\047
- 还要检查GNU文档
sed 1d
跳过第一行,使用cut
获取第五个字段,并使用printf
对唯一的排序结果进行marmatting:
printf "'%s'\n" $(sed 1d Err_Call_sipregtracking.csv | cut -d~ -f5 | sort -u)
这无法满足您将其作为一行获取的请求:
printf "'%s'," $(sed 1d Err_Call_sipregtracking.csv | cut -d~ -f5 | sort -u)|sed 's/,$//'
您的命令是正确的,但需要稍加修改,如下所示:
cat Err|u Call|sipregtracking | awk-F'~'''{print$5}'| uniq | sed 1d | sed-n-e'H${x;s/\n/,/g;s/^,//;p;}'
注意cat文件| awk'things'
不是必需的<代码>awk'things'文件就足够了。它很有趣;但是,请注意,awk
可以在内部处理大部分问题。一般来说,管道化这么多命令被认为是不好的做法,因为它需要更多的CPU时间;然而,我发现管道更容易一步一步地解释;此外,这些命令远远超出了awk
和文本处理的范围,对于大多数使用,CPU在这里应该不是什么大问题。话虽如此,我理解你的观点。是的,我想这是一个平衡的问题,事实上,小命令的好处是一个人只做一件事。我目前的答案有点过于复杂,因为我只想使用awk
。但是,在您的回答中,例如,第一个管道可以通过简单的NR>1
移除,也可以通过将项目放入数组中来移除uniq
。语句这些命令远远超出了awk的范围,文本处理
是错误的。此操作所需的命令对于文本处理来说非常普通,并且在awk中经常使用。@sjsam如何使用?我看不见。@fedorqui--非常感谢这是一种非常合理的方法,注意事项是内存使用和输出顺序,但是FWIW我会将结尾部分写为awk-F'~''NR>1{item[$5]}END{for(I in item)printf”%s\047%s\047“,(++c>1?”,“:”),I;print'}文件
。IMHOprint“\'''i”\''''
更清楚地写为print“\047”i“\047”
btw。您应该始终使用八进制,而不是十六进制转义码-请参阅。@EdMorton立即喜欢该页。awk'BEGIN{print“\x27foo!\x27”}
非常清楚:)我喜欢您使用-vq=“””
打印这些单引号的方式。它看起来更容易阅读。1)在-v
和变量名之间不留空格会使脚本不必要地呆呆特定。2) 测试唯一性的惯用方法是将数组命名/填充为!查看[$5]+
。3) 如果没有终止换行符,输出就不是POSIX中的文本,因此会从以后解析它的任何工具中邀请未定义的行为。4) 不要添加内容,然后再将其删除(例如逗号),因为它很容易出错。5) 您不需要执行shell操作来更改awk输出,只需将其保留在awk中即可。6) 要在awk脚本中获得一个单引号,请使用octal\047
——这比变量麻烦得多。@fedorqui在“
中使用变量通常会使脚本编写更加困难。例如,查找'foo.bar'
将是$0~(q“foo\\.bar”q)
vs/\047foo\.bar\047/
。请注意,第一个转义中需要额外的转义,另外还需要显式地在前面加上$0~
,并且它使用的字符串连接非常慢。不客气。不是空字符(\0
),不是换行符(\n
,对于UNIX应用程序来说更不常见,\r\n
)printf”“
将不会产生这两种结果,但是print”“
将产生适当的换行符(如ORS
中所设置的)。我只是想指出,换行符可能是\n
或\r\n
,以说明为什么要使用print”“
(它使用当前/适当的or
设置),而不是硬编码您认为换行符应该使用printf“\n”
,以防您考虑这样做。老实说,idk,如果POSIX shell需要能够从不包含终止换行符的输入处理设置变量。我怀疑不是因为按照POSIX,一行是“零个或多个非字符加上一个终止字符的序列”,而是idk。POSIX文章只是规范,请参阅上的讨论。
printf "'%s'," $(sed 1d Err_Call_sipregtracking.csv | cut -d~ -f5 | sort -u)|sed 's/,$//'
$ awk -F'~' 'NR>1 && !seen[$5]++{printf "%s\047%s\047", (NR>2 ? "," : ""), $5} END{print ""}' file
'BDA_CA_Code','ARN_Code','ALL'