在unix中获取逗号分隔的不同值

在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

我有一个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_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
    省略第一行
  • awk-F'~'''{$5=“\'$5”\”;print$5}'
    提取第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'}文件
    。IMHO
    print“\'''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'