根据从文本文件中获取的模式将文本文件拆分为多个部分

时间:2012-02-28 03:33:08

标签: linux bash text

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

$ 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

本。

3 个答案:

答案 0 :(得分:3)

这是一个简单的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. 表示所有行,写入当前输出文件

答案 1 :(得分:1)

这应该可以完成工作 - 在没有大量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),你将遇到麻烦 - 解决这个问题会有点困难 - 为读者留下了一点......

答案 2 :(得分:0)

如果每次运行的行数不变,您可以使用:

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