【问题标题】:Convert text file into a comma delimited string将文本文件转换为逗号分隔的字符串
【发布时间】:2019-04-05 05:09:58
【问题描述】:

我似乎没有找到与这个确切问题匹配的 SO 问题。

我有一个文本文件,每行有一个文本标记,没有任何逗号、制表符或引号。我想根据文件内容创建一个逗号分隔的字符串。

输入:

one
two
three

输出:

one,two,three

我正在使用这个命令:

csv_string=$(tr '\n' ',' < file | sed 's/,$//')

有没有更有效的方法来做到这一点?

【问题讨论】:

  • 请注意,如果您的值已经包含逗号、双引号甚至换行符,您应该已经定义了行为。然后,下面提供的大多数答案将产生无效输出(其代码过于简化)。如果示例中的下一行是 four (not "for")(16 个字符)怎么办?

标签: bash awk sed csv


【解决方案1】:

执行此操作的常用命令是paste

csv_string=$(paste -sd, file.txt)

【讨论】:

    【解决方案2】:

    您可以完全使用 bash 参数扩展运算符而不是使用 trsed

    csv_string=$(<file)               # read file into variable
    csv_string=${csv_string//$'\n'/,} # replace \n with ,
    csv_string=${csv_string%,}        # remove trailing comma
    

    【讨论】:

      【解决方案3】:

      Awk 的一种方法是重置 RS 并将记录视为由空行分隔。这将处理带有空格的单词并按预期将它们格式化为 CSV 格式。

      awk '{$1=$1}1' FS='\n' OFS=',' RS= file
      

      {$1=$1} 是一种基于对字段 (FS/OFS) 和/或记录分隔符 (RS/ORS) 的修改来重构文件每一行中的字段 ($0) 的方法。尾随的1 是打印每一行,并在{..} 中完成修改。

      【讨论】:

        【解决方案4】:

        使用 Perl 单行代码:

        $ cat csv_2_text
        one
        two
        three
        $ perl -ne '{ chomp; push(@lines,$_) } END { $x=join(",",@lines);  print "$x" }' csv_2_text
        one,two,three
        
        $ perl -ne ' { chomp; $_="$_," if not eof ;printf("%s",$_) } ' csv_2_text
        one,two,three
        $
        

        来自@codeforester

        $ perl -ne 'BEGIN { my $delim = "" } { chomp; printf("%s%s", $delim, $_); $delim="," } END { printf("\n") }' csv_2_text
        one,two,three
        $
        

        【讨论】:

        • @codeforester.. 请考虑对答案进行投票。 Perl 解决方案始终是可移植的,您可以信赖它们。
        • Nitpick:我们不能在读取循环本身中打印值,而不必将值存储在数组中吗?
        • 是的..它可以完成..在这种情况下,我会有额外的逗号,我必须用 sed 管道删除它..刚刚更新了答案
        • 我刚刚找到了方法..可以用eof来完成..更新了答案
        • 当您必须将其通过管道传输到另一个进程(如 sed)时,它就不再是 Perl 单线了。这个怎么样? perl -ne 'BEGIN { my $delim = "" } { chomp; printf("%s%s", $delim, $_); $delim="," } END { printf("\n") }'?
        【解决方案5】:

        在 Linux 机器上测试了四种方法 - Bash onlypasteawkPerl,以及问题中显示的tr | sed 方法:

        #!/bin/bash
        
        # generate test data
        seq 1 10000 > test.file
        
        times=${1:-50}
        
        printf '%s\n' "Testing paste solution"
        time {
            for ((i=0; i < times; i++)); do
              csv_string=$(paste -sd, test.file)
            done
        }
        
        printf -- '----\n%s\n' "Testing pure Bash solution"
        time {
            for ((i=0; i < times; i++)); do
              csv_string=$(<test.file)          # read file into variable
              csv_string=${csv_string//$'\n'/,} # replace \n with ,
              csv_string=${csv_strings%,}       # remove trailing comma
            done
        }
        
        printf -- '----\n%s\n' "Testing Awk solution"
        time {
            for ((i=0; i < times; i++)); do
              csv_string=$(awk '{$1=$1}1' FS='\n' OFS=',' RS= test.file)
            done
        }
        
        printf -- '----\n%s\n' "Testing Perl solution"
        time {
            for ((i=0; i < times; i++)); do
              csv_string=$(perl -ne '{ chomp; $_="$_," if not eof; printf("%s",$_) }' test.file)
            done
        }
        
        printf -- '----\n%s\n' "Testing tr | sed solution"
        time {
            for ((i=0; i < times; i++)); do
              csv_string=$(tr '\n' ',' < test.file | sed 's/,$//')
            done
        }
        

        令人惊讶的是,仅 Bash 的解决方案效果很差。 paste 排在首位,其次是 tr | sedAwkperl

        Testing paste solution
        
        real    0m0.109s
        user    0m0.052s
        sys 0m0.075s
        ----
        Testing pure Bash solution
        
        real    1m57.777s
        user    1m57.113s
        sys 0m0.341s
        ----
        Testing Awk solution
        
        real    0m0.221s
        user    0m0.152s
        sys 0m0.077s
        ----
        Testing Perl solution
        
        real    0m0.424s
        user    0m0.388s
        sys 0m0.080s
        ----
        Testing tr | sed solution
        
        real    0m0.162s
        user    0m0.092s
        sys 0m0.141s
        

        由于某些原因,csv_string=${csv_string//$'\n'/,} 在运行 Bash 4.4.23 的 macOS Mojave 上挂起。


        相关帖子:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-11-18
          • 2018-08-16
          • 2013-09-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-18
          相关资源
          最近更新 更多