【问题标题】:linux sed command - adding string on every end of the line of csvlinux sed 命令 - 在 csv 行的每一端添加字符串
【发布时间】:2015-04-12 23:57:07
【问题描述】:

目前我在 ff CSV 数据上遇到问题。

COLUMN1,COLUMN2,COLUMN3,COLUMN4
apple1,apple2,apple3,apple4
banana1,banana2,banana3,
caimito1,"caimito21
caimito22","caimito31
caimito32",caimito4

看起来像这样:

╔══════════╦═══════════╦═══════════╦══════════╗
║ COLUMN1  ║  COLUMN2  ║  COLUMN3  ║ COLUMN4  ║
╠══════════╬═══════════╬═══════════╬══════════╬
║ apple1   ║ apple2    ║ apple3    ║ apple4   ║
║ banana1  ║ banana2   ║ banana3   ║          ║
║ caimito1 ║ caimito21 ║ caimito31 ║ caimito4 ║
║          ║ caimito22 ║ caimito32 ║          ║
╚══════════╩═══════════╩═══════════╩══════════╝

所以我的计划是添加 COLUMN5,它的每一行都有一个值“FRUIT”。

使用的命令:

sed "1 s/$/,COLUMN5/g" FILE.csv | sed "2,$ s/$/,FRUIT/g" > OUTPUT.csv

输出:

╔══════════╦════════════════╦════════════════╦══════════╦═════════╗
║ COLUMN1  ║  COLUMN2       ║  COLUMN3       ║ COLUMN4  ║ COLUMN5 ║
╠══════════╬════════════════╬════════════════╬══════════╬═════════╣
║ apple1   ║ apple2         ║ apple3         ║ apple4   ║ FRUIT   ║
║ banana1  ║ banana2        ║ banana3        ║          ║ FRUIT   ║
║ caimito1 ║ caimito21FRUIT ║ caimito31FRUIT ║ caimito4 ║ FRUIT   ║
║          ║ caimito22      ║ caimito32      ║          ║         ║
╚══════════╩════════════════╩════════════════╩══════════╩═════════╝

有什么方法可以在不影响“caimito”行的情况下添加“FRUIT”?

我也试过ff。命令,但没有成功。在“$”之前添加了“,”。

sed "1 s/$/,COLUMN5/g" FILE.csv | sed "2,$ s/,$/,FRUIT/g" > OUTPUT.csv

【问题讨论】:

  • 2 sed 管道可以用 1 替换,操作由 ; 分隔,就像这样 sed '1 action1; 2,$ action2' yourfile

标签: linux unix csv sed


【解决方案1】:

Sed 可能不是处理 csv 文件的正确工具,因为规则比它看起来要复杂得多(这可能是可能的,但这样的脚本通常很容易出错等)。但是,您可以使用 csvtools 来处理此问题:

file="FILE.csv"
nr=$(csvtool height $file)
ot=$(perl -e "print \"COLUMN5\\n\";for\$i(2..$nr){print \"FRUIT\\n\";}")
echo "$ot" | csvtool paste "$file" -

脚本的工作原理如下:

  1. 首先我们用csvtool height计算行数,
  2. 接下来,我们通过打印 COLUMN5 后跟 n-1FRUIT 来生成附加列。
  3. 最后我们将该内容粘贴到文件的右侧。

【讨论】:

    【解决方案2】:

    编辑:我只看到了 csvtool 解决方案;它当然更实用。我之所以放弃这个解决方案,主要是因为隐藏它和它的洛夫克拉夫特式美感会很可惜。

    嗯,就这样吧。这是在 sed 中执行此操作的一种方法:

    sed ':a $!{ N; ba }; s/"[^"]*"/{&}/g; :b s/\({"[^"]*\)\n\([^"]*"}\)/\1~"~\2/g; tb; s/\n\|$/,FRUIT&/g; s/,FRUIT\(\n\|$\)/,COLUMN5\1/; :c s/\({"[^"]\)*~"~/\1\n/g; tc; s/{"\|"}/"/g' filename
    

    这将是一段旅程。它的工作原理如下:

    :a $!{ N; ba }                         # assemble the whole file in the
                                           # hold buffer
    
    s/"[^"]*"/{&}/g                        # encase all "-enclosed fields in
                                           # {"..."} to make matching the beginning
                                           # and end separately possible.
    
    :b                                     # jump mark for looping
    s/\({"[^"]*\)\n\([^"]*"}\)/\1~"~\2/g   # replace the first newline in all
                                           # {"..."} fields with ~"~
    tb                                     # loop until all were replaced
    
    s/\n\|$/,FRUIT&/g                      # Put FRUIT at the end of all lines
    s/,FRUIT\(\n\|$\)/,COLUMN5\1/          # Replace the first ,FRUIT with ,COLUMN5
                                           # The \(\n\|$\) bit is so that this
                                           # works with empty files (that only
                                           # have a header line)
    
    :c                                     # Jump mark for looping
    s/\({"[^"]\)*~"~/\1\n/g                # replace the first ~"~ in all {"..."}
                                           # fields with a newline
    tc                                     # loop until all were replaced
    
    s/{"\|"}/"/g                           # replace all {", "} markers with "
                                           # again.
    

    【讨论】:

      【解决方案3】:
      sed '1 {
         s/$/,COLUMN5/
         b
         }
      :load
      /^\([^"]*"[^"]*"\)*[^"]*"[^"]*$/ {
         N
         b load
         }
      s/$/,,,,/;s/^\(\([^,]*,\)\{4\}\).*/\1FRUIT/' YourFile
      
      • 在第一行添加COLUMN5而不是循环(b
      • 如果打开的" 在当前工作缓冲区中,请加载新行并重试
      • 默认添加4个,
      • , 分隔第一组4 并添加FRUIT
      • (循环)

      posix 版本所以--posix 在 GNU sed 上

      对于 "valid" csv(1 行所有参数由 , 分隔),只需删除加载循环部分

      【讨论】:

        猜你喜欢
        • 2013-05-02
        • 1970-01-01
        • 2017-11-04
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多