【问题标题】:How to add a header to text file in bash?如何在bash中向文本文件添加标题?
【发布时间】:2019-02-02 07:15:45
【问题描述】:

我有一个文本文件,想在转换之前将其转换为 csv 文件,我想在文本文件中添加一个标题,以便 csv 文件具有相同的标题。我在文本文件中有一千列,想要有一千列名。附带说明一下,文本文件的内容只是由逗号“,”分隔的一些数字的行。有没有办法在bash中添加标题行?

我尝试了以下方法,但没有成功。我首先在python中执行了以下命令。

> for i in range(1001):
   > print "col" + "_" + "i"

使用此命令(python header.py >> header.txt)将其输出保存在文本文件中,并将其以文本文件格式的输出添加到我拥有的原始文本文件中,如下所示:

cat header.txt 文件名.txt > newfilename.txt

然后使用“mv newfilename.txt newfilename.csv”将 txt 文件转换为 csv 文件。 但不幸的是,这种方式不起作用,因为由于某种原因,标题行的其他行数是双倍的。对于解决此问题的任何帮助,我将不胜感激。

【问题讨论】:

  • 是的,有很多方法!如果你需要一个具体的答案,你应该问一个具体的问题。标题来自哪里。如何将文本文件转换为 csv?当前字段分隔符等是什么
  • 您粘贴的内容看起来像 python 代码,而不是 bash。出于某种原因,您不想在 python 中执行此操作吗?
  • @paulski 我不知道如何在 bash 中做到这一点。这就是为什么我最终在 python 中做这部分工作。
  • 这一行可能是一个问题:python header.py >> header.txt,它附加到 header.txt 而不是替换内容。您的 header.txt 中是否只有一行?

标签: bash csv header text-files


【解决方案1】:

您可以使用以下选项之一在 bash 中生成列名。每个示例都会生成一个 header.txt 文件。您已经有代码可以将其作为标题添加到文件的开头。

使用 bash 循环

这么多次迭代的 Bash 循环效率低下,但会起作用。

for i in {1..10}; do
  echo -n "col_$i "
done > header.txt
echo >> header.txt

或使用seq

for i in $(seq 1 1000); do
  echo -n "col_$i "
done > header.txt
echo >> header.txt

仅使用 seq

单独使用 seq 会更有效。

seq -f "col_%g" -s" " 1 1000 > header.txt

【讨论】:

  • seq 支持序列前缀。您的解决方案需要 1,000 次迭代,这似乎是不必要的低效。另外,如果你无论如何都要循环,为什么不使用以 Bash 为中心的 for i in {1..1001} 而不是生成 seq?
【解决方案2】:

根据您的文件已经用逗号分隔的描述,csv 文件也是如此。您只想添加一个列号标题行。

$ awk -F, 'NR==1{for(i=1;i<=NF;i++) printf "col_%d%s", $i,(i==NF?ORS:FS)}1' file

将添加与文件第一行中的字段一样多的列标题

例如

$ seq 5 | paste -sd, |      # create 1,2,3,4,5 as a test input
  awk -F, 'NR==1{for(i=1;i<=NF;i++) printf "col_%d%s", i, (i==NF?ORS:FS)}1'

col_1,col_2,col_3,col_4,col_5
1,2,3,4,5

【讨论】:

    【解决方案3】:

    使用 seq 和 sed

    您可以使用 seq 实用程序来构建您的 CSV 标头,并借助 Bash 扩展的一些小帮助。然后,您可以将新的标题行插入到现有的 CSV 文件中,或者将标题与您的数据连接起来。

    例如:

    # construct a quoted CSV header
    columns=$(seq -f '"col_%g"' -s', ' 1 1001)
    
    # strip the trailing comma
    columns="${columns%,*}"
    
    # insert headers as first line of foo.csv with GNU sed
    sed -i -e "1 i\\${columns}" /tmp/foo.csv
    

    注意事项

    如果您没有 GNU sed,您也可以使用 cat、spond 或其他工具连接您的标头和数据,尽管您的大多数连接选项需要重定向到新的组合文件以避免破坏现有数据.

    例如,将 /tmp/data.csv 作为您的原始数据文件:

    seq -f '"col_%g"' -s', ' 1 1001 > /tmp/header.csv
    sed -i -e 's/,[[:space:]]*$//' /tmp/header.csv
    cat /tmp/header /tmp/data > /tmp/new_file.csv
    

    另外,请注意,虽然可以避免调用标准实用程序的 Bash 解决方案是可行的,但在纯 Bash 中执行此操作对于大型数据集而言可能太慢或占用大量内存。

    您的里程可能会有所不同。

    【讨论】:

    • 感谢您的详细回复。但是我从第三行代码得到了下面的错误!
    • -bash: /bin/sed: 参数列表太长
    • @user8034918 这是系统特定的限制;这个对我有用。根据我的回答,如果由于参数列表限制而无法使用 GNU sed 或将其作为就地编辑工作,那么只需连接头文件和数据文件。
    • @user8034918 另见this answer 关于“参数列表太长”和using built-ins as workarounds
    【解决方案4】:
    printf "col%s," {1..100} |
    sed 's/,$//' |
    cat - filename.txt >newfilename.txt
    

    我相信sed 应该提供缺少的最终换行符作为副作用。如果没有,也许可以试试's/,$/\n/',尽管这也不是完全可移植的。您也可以将cat 替换为sed,类似于

    ... | sed 's/,$//;r filename.txt'
    

    但同样,我不完全确定它的便携性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-01
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-05
      • 2019-07-31
      • 2011-10-08
      相关资源
      最近更新 更多