繁体   English   中英

将字符串分隔的行拆分为新文件作为列 Bash 脚本

[英]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 中搜索,但没有得到我想要的。

带有prgrep和带有 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)'
  • $( )称为命令替换
  • tspr的选项,请参阅: 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解决方案。


  • 对于大数据大小/文件,我会用 go 和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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM