【问题标题】:split file by lines and keep the first string as a header for output files按行拆分文件并将第一个字符串保留为输出文件的标题
【发布时间】:2020-08-21 17:16:28
【问题描述】:

我有这样的文件:

t_#_3_0 v_0_17  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
t_#_3_1 v_0_144 v_1_17  v_2_20  u_0_1   u_0_2   u_1_2
t_#_3_2 v_0_143 v_1_233 v_2_238 u_0_1   u_0_2   u_1_2
t_#_3_3 v_0_20  v_1_253 v_2_275 u_0_1   u_0_2   u_1_2
t_#_3_4 v_0_144 v_1_209 v_2_90  u_0_1   u_0_2   u_1_2
t_#_3_5 v_0_144 v_1_209 v_2_30  u_0_1   u_0_2   u_1_2
t_#_3_6 v_0_19  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
t_#_3_7 v_0_20  v_1_7   v_2_78  u_0_1   u_0_2   u_1_2
t_#_3_8 v_0_16  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
t_#_3_9 v_0_15  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2

我想将它逐行拆分,并将第一个字符串保留为我的新文件的标题。我想要的输出应该是这样的。

file 1: t_#_3_0.txt (inside located line - t_#_3_0 v_0_17 v_1_20 v_2_78 u_0_1 u_0_2 u_1_2)
file 2: t_#_3_1.txt
file 3: t_#_3_2.txt

我尝试了split 命令,但它导致输出文件的数字索引。

非常感谢您的建议!

谢谢!

欧哈

【问题讨论】:

    标签: bash awk split


    【解决方案1】:

    使用 GNU awk:

    awk '{name=$1 ".txt"; print >name; close(name)}' file
    

    变量name 包含后缀为.txt 的第一列的内容。 print >name 将完整的当前行写入文件 name

    【讨论】:

      【解决方案2】:

      这些结果让我有点吃惊。 :)

      sed

      只是从工具箱中取出一些奇怪的东西作为为什么你应该不时评估你的方法的例子......

      $: time sed -En 's/^([^ ]+)( .*)$/printf "%s%s\n" "\1" "\2" > \1.txt/e' file
      real    0m0.859s
      user    0m0.183s
      sys     0m0.480s
      

      我认为这会很慢,但为了以防万一,最好在工具箱中提供。不要用钳子打钉子。

      awk

      $: time awk '{ fn=$1".txt" ; print > fn ; close (fn) } ' file
      real    0m0.141s
      user    0m0.031s
      sys     0m0.077s
      

      可以预见的更快,对于更大的文件可能会更快。

      但是让我吃惊的那个-

      bash

      $: time while read line; do echo "$line" > "${line%%[   ]*}"; done < file
      real    0m0.015s
      user    0m0.000s
      sys     0m0.016s
      

      注意 - 已编辑以使用空格和/或制表符

      "${line%%[ ]*}" 在方括号[ ] 之间有一个空格和一个制表符作为字段分隔符。

      我认为这里的时间增益在于文件管理开销。 read 是出了名的慢,但我想操作系统擅长处理自己的 I/O。

      也许有人可以提供更深入的分析?

      将测试细化到 10k 条记录的样本大小可以大大缩小 bashawk 之间的差距 -

      $: for x in {0..9999}; do echo "t_${x}_3_0 v_0_17  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2"; done >| file
      
      $: time while read line; do echo "$line" > "${line%% *}"; done < file
      real    0m24.022s
      user    0m2.360s
      sys     0m11.938s
      
      $: time awk '{ fn=$1".txt" ; print > fn ; close (fn) } ' file
      real    0m27.284s
      user    0m1.312s
      sys     0m12.656s
      
      $: $: time sed -En 's/^([^ ]+)( .*)$/printf "%s%s\n" "\1" "\2" > \1.txt/e' file
      real    13m28.503s
      user    1m48.374s
      sys     8m22.970s
      

      我怀疑与较小数据集的很多区别是awk 的编译时间,也许吧?

      测试 100k 以确认 -

      $: wc -c file # >5.5MB
      5788890 file
      

      bash:

      real    8m42.666s
      user    0m28.671s
      sys     2m34.781s
      

      awk:

      real    8m15.096s
      user    0m15.546s
      sys     2m35.421s
      

      我真的很惊讶差异如此之小。
      我认为这是因为大部分时间是文件 I/O 操作。

      【讨论】:

      • 样本数据太小,无法用于基准测试。让它达到几兆字节,awk 会更快,sed 没有机会,因为它为每一行生成一个新的 sh 实例。这里没有什么可分析的
      • 所以,我尝试在另一组行上运行它,但它不会产生输出。我认为你的问题是行中实体之间的分隔符。我说的对吗?
      • 是空格还是制表符?
      • 这是我测试过的输入示例:t_#_3_72 v_0_233 v_1_222 v_2_51 v_3_85 u_0_1 u_0_2 u_0_3 t_#_3_73 v_0_233 v_1_222 v_2_51 v_3_55 u_0_1 u_0_2 u_0_3 t_#_3_74 v_0_233 v_1_222 v_2_51 v_3_54 u_0_1 u_0_2 u_0_3 t_#_3_75 v_0_238 v_1_137 v_2_214 v_3_50 u_0_1 u_0_2 u_0_3
      • 它有制表符和空格分隔符
      【解决方案3】:

      我对需求的理解:

      • 源文件中的每一行都将被复制到一个新文件中
      • 新文件以字段(列)#1 的内容命名

      一个awk 解决方案(假设原始数据在文件file.all 中):

      $ awk '{ fn=$1".txt" ; print > fn ; close (fn) } ' file.all
      $ for f in t*#*txt
      do
      echo "+++++++++++++ $f"
      cat $f
      done
      
      +++++++++++++ t_#_3_0.txt
      t_#_3_0 v_0_17  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_1.txt
      t_#_3_1 v_0_144 v_1_17  v_2_20  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_2.txt
      t_#_3_2 v_0_143 v_1_233 v_2_238 u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_3.txt
      t_#_3_3 v_0_20  v_1_253 v_2_275 u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_4.txt
      t_#_3_4 v_0_144 v_1_209 v_2_90  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_5.txt
      t_#_3_5 v_0_144 v_1_209 v_2_30  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_6.txt
      t_#_3_6 v_0_19  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_7.txt
      t_#_3_7 v_0_20  v_1_7   v_2_78  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_8.txt
      t_#_3_8 v_0_16  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
      +++++++++++++ t_#_3_9.txt
      t_#_3_9 v_0_15  v_1_20  v_2_78  u_0_1   u_0_2   u_1_2
      

      【讨论】:

      • 看起来@Cyrus 用相同的解决方案击败了你一分钟。
      猜你喜欢
      • 2020-02-03
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 2018-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多