[英]Split lines delimited by string into new files as columns Bash script
我有一个如下的数据文件:
>> cat file1.txt
@target G0.S0
1 6
1 4
4 2
@target G0.S0
2 4
8 9
5 7
@target G0.S0
3 5
0 9
3 7
我想在一个新文件中创建由@target G0.S0
分隔的拆分列,其中列设置一个紧挨着前面的列,如下所示:
>> cat file2.txt
1 6 2 4 3 5
1 4 8 9 0 9
4 2 5 7 3 7
我在 inte.net 中搜索,但没有得到我想要的。
带有pr
、 grep
和带有 shell 的tail
的快速单行代码。
pr "-$(grep -Fc '@target G0.S0' file1.txt)ts"' ' file1.txt | tail -n +2
将 output 重定向到新文件。
pr ... > file2.txt
让我们分解一下。
pr
是一个打印实用程序。grep -Fc '@target G0.S0' file1.txt
扩展为数字请参阅: grep --help | grep -E -- ' -(F|c)'
grep --help | grep -E -- ' -(F|c)'
$( )
称为命令替换。t
和s
是pr
的选项,请参阅: pr --help | grep -E -- '^ *-(s|t)'
pr --help | grep -E -- '^ *-(s|t)'
tail
从第二行开始打印,参见: tail --help | grep -- -n
tail --help | grep -- -n
pr -Nts' '
,其中N
是一个整数/数字。 正如@Socowi
所提到的,它有很多限制。 该代码假设@target G0.S0
之间的所有行都是相等/相同数量的行,在本例中为@target G0.S0
之间的 3 行。 (这是我基于答案的地方),如果(长数据/输入)大小太多,则应添加一个附加选项,即-w
。 就像我提到的,如果文件/数据/大小/输入很大/很大,那么首选awk
解决方案。
awk
代替。使用awk
,假设步幅为 4 并将脚本命名为concat
并授予其执行权限:
#! /usr/bin/awk -vN=4 -f
(NR-1)%N==0 {next}
{i=int(NR-2)%N;a[i]=(a[i] ? a[i] " " : "") $0}
END {for (i=0; i<N; i++){print a[i]}}
然后
./concat file1.txt > file2.txt
给
1 6 2 4 3 5
1 4 8 9 0 9
4 2 5 7 3 7
在file2.txt
中
单awk
程序解决方案
以下建议将行累积到一个数组中,该数组通过引用行号进行索引(用于循环索引 1-3 的递减和余数除法,存储行 2-4、6-8、10-12 等,每次连接)。 主块之前的条件不包括第 1、5、9 行等。END 块迭代数组以打印 output,它被重定向到所需的新文件名。
awk ' (NR-1)%4!=0{lines[(NR-1)%4]=lines[(NR-1)%4]$0}
END{ for(line=1; line<4; line++) {print lines[line]}
} ' file1.txt > file2.txt
这可能对你有用(csplit、粘贴和 sed):
csplit -qz --suppress file '/@target/' '{*}' && paste -d' ' xx* |
sed 's/ / /g' >outFile && rm xx*
将输入文件拆分为连续编号的文件,每行包含要追加的每一列。
粘贴中间文件,以空格分隔。
从上面的 output 中取出额外的空格, output 到最终文件并清理。
一个 GNU sed 唯一的解决方案:
sed -nE '/\n/!{:a;N;$!ba}
s/^@/\n@/;s/\S$/& /mg;tb
:b;s/^([^\n]*)((\n[^@]*)*)\n@[^\n]*\n([^\n]+)/\1\4\2\n/;tb
s/ \n/\n/;P;s/\n+$//;s/\n\n/\n@\n/g;D' file
如果文件没有被 slurp 到模式空间(内存),则 slurp 文件。
在模式空间的开头引入一个换行符,并在每行的末尾提供一个空格。
遍历文件,将 header 行之后的第一行中的值附加到模式空间的第一行。 替换每个 header,因为它由两个换行符处理。
删除行尾引入的空格并打印模式空间的第一行。
如果所有行都已处理,则模式空间的末尾将仅包含换行符,在这种情况下将其删除。
否则,通过在每次出现的两个换行符之间插入一个@
来重新引入伪 header。
如果还有要处理的行,则删除打印的行并再次开始 sed 过程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.