使用bash以逗号分隔字段

时间:2014-05-30 21:26:56

标签: bash awk sed

如何在字段之间放置逗号?

输入数据

12123 'QA test case 1' 'QA environment'   
12234 'UAT test case 1' 'UAT environment'  

预期输出

12123, 'QA test case 1', 'QA environment'   
12234, 'UAT test case 1', 'UAT environment'  

8 个答案:

答案 0 :(得分:3)

另一种选择是使用CSV解析器:

ruby -rcsv -ne '
  puts CSV.generate_line(
         CSV.parse_line($_.strip, {:col_sep => " ", :quote_char => "'\''"}
       ), {:force_quotes => 1}) 
'  file
"12123","QA test case 1","QA environment"
"12234","UAT test case 1","UAT environment"

答案 1 :(得分:2)

一个天真的bash实现,假设没有(转义的)'个实例字段中出现:

  • 保留原始单引号。
  • 接受任意数量的输入字段。
  • 任何字段都可以单引号。
  • 警告:字段之间的空格被规范化(每个空格替换为一个空格), in 引用字段中的空格。

假设输入来自文件file

# Read all whitespace-separated tokens (potentially across quoted field boundaries).
while read -ra tkns; do  
  # Initialize per-line variables.
  numTkns=${#tkns[@]} i=0 inField=0
  # Loop over all tokens.
  for tkn in "${tkns[@]}"; do
    # Determine if we're inside a quoted field.
    [[ $tkn == \'* ]] && inField=1
    [[ $tkn == *\' ]] && inField=0
    # Determine the output separator:
    if (( ++i == numTkns )); then
      sep=$'\n' # last token, terminate output line with \n
    else
      # inside a field: use just a space; between fields: use ', '
      (( inField )) && sep=' ' || sep=', '
    fi
    # Output token and separator.
    printf '%s%s' "$tkn" "$sep"
  done
done < file

答案 2 :(得分:2)

您的输入数据看起来非常像参数列表。因此,一种方便的方法是定义一个bash函数,它只是将其参数列表作为逗号分隔的标记返回,并为文件中的每一行调用它。

但是,下面的简单实现会丢失多字标记周围的引号(但它会正确放置逗号)。如果你需要那些完全相同的引号,它会变得有点复杂(输出引用的每个标记都非常容易):

#!/bin/bash
function csv_args() {
    while [ -n "$1" ]; do
        echo -n "$1"
        shift
        [ -n "$1" ] && echo -n ', '
    done
    echo
}

while read line; do
    eval csv_args $line
done < /path/to/your/file

答案 3 :(得分:2)

$ sed "s/ '/,&/g" file
12123, 'QA test case 1', 'QA environment'
12234, 'UAT test case 1', 'UAT environment'

答案 4 :(得分:1)

试试这个awk:

awk -F" '" '{ print $1, $2, $3 }' OFS=", '" data

或使用BEGIN块:

awk -F" '" 'BEGIN {OFS="," FS} { print $1, $2, $3 }' data

在任何一种情况下,FS都设置为'(空格+&#34;&#39;&#34;),OFS设置为&# 34;,&#34; + '。它基于假设'是一个有效唯一的字段分隔符,所有输入数据都按照问题格式化/排列。

答案 5 :(得分:1)

以下是我使用csv

处理awk的方法
cat file
12123 'QA test case 1' 'QA environment' some more
12234 'UAT test case 1' 'UAT environment'

awk '{for (i=1;i<NF;i++) {if ($i~t) c++;printf "%s"(c%2?FS:", "),$i}print $NF}' t=\' file
12123, 'QA test case 1', 'QA environment', some, more
12234, 'UAT test case 1', 'UAT environment'

这会记录它找到的'个。{ 如果0 2 4 6 etc您在一个群组之外,请使用,分开 如果1 3 5 7 etc您在一个群组中,请按(空格)

进行拆分

由于你现在拥有一个好的分隔符,你可以摆脱'

awk '{for (i=1;i<NF;i++) {if ($i~t) c++;sub(t,"",$i);printf "%s"(c%2?FS:","),$i}sub(t,"",$NF);print $NF}' t=\' file
12123,QA test case 1,QA environment,some,more
12234,UAT test case 1,UAT environment

您还可以使用用于定义字段的FPAT,与定义分隔符的FS相对,但是您需要gnu awk 4.x,并且它不可移植。

awk '{for (i=1;i<NF;i++) printf "%s, ",$i;print $NF}' FPAT="[^' ]+|'[^']+'" file
12123, 'QA test case 1', 'QA environment', some, more
12234, 'UAT test case 1', 'UAT environment'

FPAT="[^' ]+|'[^']+'"如何运作?
1.字段不应包含一个或多个'或空格。 [^' ]+ eks somemore
2.字段以'开头,然后是一个或多个',然后以'结尾。 '[^']+' eks 'test data'

答案 6 :(得分:0)

解决方案是遍历记录中的每个字符(while read -n 1),将每个非空格字符连接为一个元素值,并将所有字符用单引号括起来(或在您的选项中引用单引号({{ 1}})。每当你完成一个单元(到达空格或换行符)时,将它附加到一个数组。当遇到一个换行符或到达EOF时,结束记录并以你的格式打印记录数组。循环再次开始记录数组清零。

想要源代码?先告诉我你的工作。 :)

答案 7 :(得分:0)

这个解决方案(我相信)不是很好,但至少是标准的:

awk 'BEGIN{SP="[:space:]"}{gsub("(["SP"]*('\''[^'\'']*'\''|[^'\''"SP"])+)","&,");if(match($0, (",["SP"]+$")))$0=substr($0,1,RSTART-1)substr($0,RSTART+1)}1'

虽然一些“破解”的awk实现不支持[[:foo:]]样式的字符类,但在这种情况下你可以使用:

awk 'BEGIN{SP=" \t\f\v\r\n"}{gsub("(["SP"]*('\''[^'\'']*'\''|[^'\''"SP"])+)","&,");if(match($0, (",["SP"]+$")))$0=substr($0,1,RSTART-1)substr($0,RSTART+1)}1'

注意:我使用'\''来放置每个单引号字符,因为这是一种简单而标准的方法。如果要在“.awk”文件中使用此行,只需使用单引号替换每个匹配项。