【问题标题】:Split text file into parts based on a pattern taken from the text file根据从文本文件中获取的模式将文本文件拆分为多个部分
【发布时间】:2012-03-17 13:48:20
【问题描述】:

我有很多固定宽度数据的文本文件,例如:

$ head model-q-060.txt 
% x                      y                        
15.0                     0.0                      
15.026087                -1.0                     
15.052174                -2.0                     
15.07826                 -3.0                     
15.104348                -4.0                     
15.130435                -5.0                     
15.156522                -6.0                     
15.182609                -6.9999995               
15.208695                -8.0  

数据包含 3 或 4 次模拟运行,全部存储在一个文本文件中,运行之间没有分隔符。换句话说,没有空行或任何东西,例如如果每次运行只有 3 条“记录”,则运行 3 次时看起来像这样:

$ head model-q-060.txt 
% x                      y                        
15.0                     0.0                      
15.026087                -1.0                     
15.052174                -2.0                     
15.0                     0.0                      
15.038486                -1.0                     
15.066712                -2.0                     
15.0                     0.0                      
15.041089                -1.0                     
15.087612                -2.0                     

这是一个 COMSOL Multiphysics 输出文件,供感兴趣的人使用。从视觉上您可以分辨出新的运行数据从哪里开始,因为第一个 x 值是重复的(实际上整个第二行可能对所有这些数据都相同)。所以我需要首先打开文件并获取这个 x 值,保存它,然后将它用作与 awk 或 csplit 匹配的模式。我正在努力解决这个问题!

csplit 将完成这项工作:

$ csplit -z -f 'temp' -b '%02d.txt' model-q-060.txt /^15\.0\\s/ {*}

但我必须知道要拆分的模式。这个问题很相似,但我的每个文本文件可能有不同的匹配模式:Split files based on file content and pattern matching

本。

【问题讨论】:

  • 您会反对基于 python 或 perl 的解决方案吗?我希望它只有几行。
  • 接下来我正在处理python-matplotlib中的数据,所以python也会很棒!
  • 新运行的开始是自变量可以倒退的唯一时间吗?这似乎是一种比寻找重复线更可靠的检测方法。
  • Ben Voigt - 是的,很好的观察力。你是什​​么意思然后使用它?

标签: linux bash text


【解决方案1】:

这是一个简单的 awk 脚本,可以满足您的要求:

BEGIN { fn=0 }
NR==1 { next }
NR==2 { delim=$1 }
$1 == delim {
    f=sprintf("test%02d.txt",fn++);
    print "Creating " f
}

{ print $0 > f }
  1. 初始化输出文件号
  2. 忽略第一行
  3. 从第二行提取分隔符
  4. 对于第一个标记与分隔符匹配的每个输入行,设置输出文件名
  5. 对于所有行,写入当前输出文件

【讨论】:

  • 这是最优雅、最简洁的代码,谢谢!对不起,我不能和你和@icyrock.com 分分。
  • +1 以获得解释,尽管我可能需要一段时间才能弄清楚。
  • 在上面的第三行中,$1 是否将整行捕获到 delim 中?
  • 感谢 Jim,做了一些小改动,为文件添加了标题,并反转了字段输出的顺序,并转换为逗号分隔。很酷。
【解决方案2】:

这应该可以完成工作 - 在您没有很多 temp*.txt 文件的地方进行测试::)

rm -f temp*.txt

cat > f1.txt <<EOF
% x                      y                        
15.0                     0.0                      
15.026087                -1.0                     
15.052174                -2.0                     
15.0                     0.0                      
15.038486                -1.0                     
15.066712                -2.0                     
15.0                     0.0                      
15.041089                -1.0                     
15.087612                -2.0    
EOF

first=`awk 'NR==2{print $1}' f1.txt|sed 's/\\./\\\\./'`
echo --- Splitting by: $first

csplit -z -f temp -b %02d.txt f1.txt /^"$first"\\s/ {*}

for i in temp*.txt; do
  echo ---- $i
  cat $i
done

上面的输出是:

--- Splitting by: 15\.0
51
153
153
136
---- temp00.txt
% x                      y                        
---- temp01.txt
15.0                     0.0                      
15.026087                -1.0                     
15.052174                -2.0                     
---- temp02.txt
15.0                     0.0                      
15.038486                -1.0                     
15.066712                -2.0                     
---- temp03.txt
15.0                     0.0                      
15.041089                -1.0                     
15.087612                -2.0    

当然,如果您有重复的第二列值(在上面的示例中为15.0),您将会遇到麻烦 - 解决这个问题会有点困难 - 留给读者练习......

【讨论】:

  • 谢谢,干得好。在新的运行开始之前,15.0 的值不会重复,但可能会出现 15.000000。
  • 谢谢。 15.000000 将被你已经拥有的 \\s 过滤,所以你应该在那里很好。剩下的就是尝试一下...... :)
  • 我第一次使用 awk,学习了一下,但这似乎是一个好方法,即使其中一些令人眼花缭乱。我试过了,效果很好。
【解决方案3】:

如果每次运行的行数是恒定的,你可以使用这个:

cat your_file.txt | grep -P "^\d" | \
   split --lines=$(expr \( $(wc -l "your_file.txt" | \
   awk '{print $1'}) - 1 \) / number_of_runs)

【讨论】:

  • 优秀的横向思维,它应该起作用,因为在每次模拟中,每次运行都会有相同数量的“记录”。但是,我必须检查一下,因为有时我会运行 3 次,有时会运行 4 次或更多或更少。
  • 当然,那你可以改变代码中的“number_of_runs”变量来匹配
猜你喜欢
  • 2018-06-16
  • 2011-12-25
  • 1970-01-01
  • 2012-09-13
  • 2013-04-22
  • 2017-12-14
  • 1970-01-01
  • 2021-03-26
相关资源
最近更新 更多