我有一个包含3D坐标列表的长文本文件。文件的开头由如下标题组成:
10112
2455
121.417670 172.321300 1.704072
0.997697 0.067831 -0.000222
-0.067831 0.997697 0.000207
0.000236 -0.000191 1.000000
0.997697 0.067831 -0.000222 0
-0.067831 0.997697 0.000207 0
0.000236 -0.000191 1.000000 0
121.417670 172.321300 1.704072 1
之后开始坐标列表。所有行都由3到7个数字组成。例如:
0.001686 0.812066 -1.686245 0.074434
0.001695 0.816359 -1.692300 0.087190
0.001699 0.818673 -1.694508 0.097398
...
列表的总长度等于标题的前两个数字(10112 * 2455)的乘积。这些是PTX文件,包含来自文本格式的激光扫描的3D点。
重点是该文件是标题和坐标的串联,我想拆分文件在标题上打破它。理想的解决方案是将文件拆分为两个连续的单个整数行。我正在寻找使用csplit的通用解决方案,但csplit一次读取一行,因此它无法检测到两个连续的行。
作为最后的手段,我将自己编写一个软件,但我更愿意找到基于CLI工具(Awk?)的解决方案(如果有的话)。
有什么想法吗?
感谢您
假设我有一个包含以下内容的文件:
2
3
121.417670 172.321300 1.704072
0.997697 0.067831 -0.000222
-0.067831 0.997697 0.000207
0.000236 -0.000191 1.000000
0.997697 0.067831 -0.000222 0
-0.067831 0.997697 0.000207 0
0.000236 -0.000191 1.000000 0
121.417670 172.321300 1.704072 1
6.001686 0.812066 -1.686245 0.074434
3.001695 0.816359 -1.692300 0.087190
6.001699 0.818673 -1.694508 0.097398
2.001686 0.812066 -1.686245 0.074434
1.001695 0.816359 -1.692300 0.087190
0.001699 0.818673 -1.694508 0.097398
3 <--- cut before this line
1
421.417670 172.321300 1.704072
0.997697 0.067831 -0.000222
-0.067831 0.997697 0.000207
0.000236 -0.000191 1.000000
0.997697 0.067831 -0.000222 0
-0.067831 0.997697 0.000207 0
0.000236 -0.000191 1.000000 0
421.417670 172.321300 1.704072 1
1.001686 0.812066 -1.686245 0.074434
2.001695 0.816359 -1.692300 0.087190
3.001699 0.818673 -1.694508 0.097398
在这种情况下,我应该最终得到两个文件,在由单个整数组成的两行中的第一行之前剪切。
作为替代方案,知道两个单个数字行表示该部分有多少个点,我们可以说第一个输出文件由前2 * 3 + 10 = 16组成(10行标题和6个数据)行,第二个文件由随后的3 * 1 + 10 = 13(总是10行fo标题和此时3个数据行)组成。
答案 0 :(得分:1)
因此,您希望将文件拆分为不同的文件,在所有文件中打印标题。
这样做,您只需要在参数-v lines=XX
中指定要存储的行数以及要存储的标题行数-v head=YY
:
awk -v lines=5 -v head=2
'NR<=head{header[NR]=$1; next}
!((NR-3)%lines) {file="output_"++count; for (i=1;i<=head;i++) print header[i] > file}
{print > file}
' file
一衬垫:
awk -v lines=5 -v head=2 'NR<=head{header[NR]=$1; next} !((NR-3)%lines) {file="output_"++count; for (i=1;i<=head;i++) print header[i] > file} {print > file}' file
对于您的特定示例输入,提供head=2
和lines=5
,它会返回两个文件:
$ cat output_1
10112
2455
121.417670 172.321300 1.704072
0.997697 0.067831 -0.000222
-0.067831 0.997697 0.000207
0.000236 -0.000191 1.000000
0.997697 0.067831 -0.000222 0
$ cat output_2
10112
2455
-0.067831 0.997697 0.000207 0
0.000236 -0.000191 1.000000 0
121.417670 172.321300 1.704072 1
awk '(!flag && NF==1) {header[1]=$1; flag=1; next} (flag && NF==1) {header[2]=$1; flag=0; file="output_"++count; printf "%d\n%d\n", header[1], header[2] > file; next} {print > file}' file
(!flag && NF==1) {header[1]=$1; flag=1; next}
如果没有设置标志,则假设它是标题的第一行并存储它。( flag && NF==1) {header[2]=$1; flag=0; file="output_"++count; printf "%d\n%d\n", header[1], header[2] > file; next}
如果设置了标志,则表示我们已经捕获了标题的第一行,而我们在第二行。为此,请取消设置标记,生成文件名为output_
+ number
并填充存储的标题。{print > file}
在其余情况下,将当前行打印到文件中。根据您的示例文件,它会返回output_1
和output_2
:
$ cat output_1
2
3
121.417670 172.321300 1.704072
0.997697 0.067831 -0.000222
-0.067831 0.997697 0.000207
0.000236 -0.000191 1.000000
0.997697 0.067831 -0.000222 0
-0.067831 0.997697 0.000207 0
0.000236 -0.000191 1.000000 0
121.417670 172.321300 1.704072 1
6.001686 0.812066 -1.686245 0.074434
3.001695 0.816359 -1.692300 0.087190
6.001699 0.818673 -1.694508 0.097398
2.001686 0.812066 -1.686245 0.074434
1.001695 0.816359 -1.692300 0.087190
0.001699 0.818673 -1.694508 0.097398
$ cat output_2
3
1
421.417670 172.321300 1.704072
0.997697 0.067831 -0.000222
-0.067831 0.997697 0.000207
0.000236 -0.000191 1.000000
0.997697 0.067831 -0.000222 0
-0.067831 0.997697 0.000207 0
0.000236 -0.000191 1.000000 0
421.417670 172.321300 1.704072 1
1.001686 0.812066 -1.686245 0.074434
2.001695 0.816359 -1.692300 0.087190
3.001699 0.818673 -1.694508 0.097398