如何将多行转换为固定列长
How to convert multiple lines into fixed column lengths
要将行转换为制表符分隔,很容易
cat input.txt | tr "\n" " "
但我有一个包含 84046468 行的长文件。我希望将其转换为包含 1910147 行和 44 个制表符分隔列的文件。第一列是文本字符串,例如 chrXX_12345_+
,其他 43 列是数字字符串。有没有办法执行此转换?
存在 NA
,所以我猜想 sed
如果前面的字符串是数字,则用“\n”代替“\t”是行不通的。
样本input.txt
chr10_1000103_+
0.932203
0.956522
1
0.972973
1
0.941176
1
0.923077
1
1
0.909091
0.9
1
0.916667
0.8
1
1
0.941176
0.904762
1
1
1
0.979592
0.93617
0.934783
1
0.941176
1
1
0.928571
NA
1
1
1
0.941176
1
0.875
0.972973
1
1
NA
0.823529
0.51366
chr10_1000104_-
0.952381
1
1
0.973684
样本output.txt
chr10_1000103_+ 0.932203 (numbers all tab-delimited)
chr10_1000104_- etc
(sorry alot of numbers to type manually)
不是最佳解决方案,但应该可行:
line="nonempty"; while [ ! -z "$line" ]; do for i in $(seq 44); do read line; echo -n "$line "; done; echo; done < input.txt
如果文件中有空行,它将终止。对于更永久的解决方案,我会尝试 perl。
编辑:
如果你关心效率,就用awk。
awk '{ printf "%s\t", } NR%44==0{ print "" }' < input.txt
您可能想用 | sed 's/\t$//'
去除尾随制表符或使 awk 脚本更复杂。
sed '
# use a delimiter
s/^/M/
:Next
# put a counter
s/^/i/
# test counter
/^\(i\)\{44\}/ !{
$ !{
# not 44 line or end of file, add the next line
N
# loop
b Next
}
}
# remove marker and counter
s/^i*M//
# replace new line by tab
s/\n/ /g' YourFile
如果 sed 上的选项卡超过 255 个(所以 44 个就可以)
下面是使用 4 列而不是 44 列的正确方法:
$ cat file
chr10_1000103_+
0.932203
0.956522
1
chr10_1000104_-
0.952381
1
1
$ awk '{printf "%s%s", [=10=], (NR%4?"\t":"\n")}' file
chr10_1000103_+ 0.932203 0.956522 1
chr10_1000104_- 0.952381 1 1
只需将 4 更改为 44 即可作为您的实际输入。
如果您在输出中看到 control-Ms,那是因为它们存在于您的输入中,因此请在 运行 工具或使用 GNU awk 之前使用 dos2unix 或类似工具删除它们,您可以设置 -v RS='\n\r'
.
发布问题时,请务必使其尽可能清晰、简单和简短,以便尽可能多的人有兴趣帮助您。
顺便说一句,cat input.txt | tr "\n" " "
是一个 UUOC,应该只是 tr "\n" " " < input.txt
这可能适合您 (GNU sed):
sed '/^chr/!{H;$!d};x;s/\n/\t/gp;d' file
如果一行不是以 chr
开头,则将其添加到保留 space 中,然后将其删除,除非它是最后一行。如果该行确实开始 chr
或者它是最后一行,则交换到保留 space 并用制表符替换所有换行符并打印出结果。
N.B。下一行的开头将在模式 space 中保持不变,成为新的保留 space.
要将行转换为制表符分隔,很容易
cat input.txt | tr "\n" " "
但我有一个包含 84046468 行的长文件。我希望将其转换为包含 1910147 行和 44 个制表符分隔列的文件。第一列是文本字符串,例如 chrXX_12345_+
,其他 43 列是数字字符串。有没有办法执行此转换?
存在 NA
,所以我猜想 sed
如果前面的字符串是数字,则用“\n”代替“\t”是行不通的。
样本input.txt
chr10_1000103_+
0.932203
0.956522
1
0.972973
1
0.941176
1
0.923077
1
1
0.909091
0.9
1
0.916667
0.8
1
1
0.941176
0.904762
1
1
1
0.979592
0.93617
0.934783
1
0.941176
1
1
0.928571
NA
1
1
1
0.941176
1
0.875
0.972973
1
1
NA
0.823529
0.51366
chr10_1000104_-
0.952381
1
1
0.973684
样本output.txt
chr10_1000103_+ 0.932203 (numbers all tab-delimited)
chr10_1000104_- etc
(sorry alot of numbers to type manually)
不是最佳解决方案,但应该可行:
line="nonempty"; while [ ! -z "$line" ]; do for i in $(seq 44); do read line; echo -n "$line "; done; echo; done < input.txt
如果文件中有空行,它将终止。对于更永久的解决方案,我会尝试 perl。
编辑:
如果你关心效率,就用awk。
awk '{ printf "%s\t", } NR%44==0{ print "" }' < input.txt
您可能想用 | sed 's/\t$//'
去除尾随制表符或使 awk 脚本更复杂。
sed '
# use a delimiter
s/^/M/
:Next
# put a counter
s/^/i/
# test counter
/^\(i\)\{44\}/ !{
$ !{
# not 44 line or end of file, add the next line
N
# loop
b Next
}
}
# remove marker and counter
s/^i*M//
# replace new line by tab
s/\n/ /g' YourFile
如果 sed 上的选项卡超过 255 个(所以 44 个就可以)
下面是使用 4 列而不是 44 列的正确方法:
$ cat file
chr10_1000103_+
0.932203
0.956522
1
chr10_1000104_-
0.952381
1
1
$ awk '{printf "%s%s", [=10=], (NR%4?"\t":"\n")}' file
chr10_1000103_+ 0.932203 0.956522 1
chr10_1000104_- 0.952381 1 1
只需将 4 更改为 44 即可作为您的实际输入。
如果您在输出中看到 control-Ms,那是因为它们存在于您的输入中,因此请在 运行 工具或使用 GNU awk 之前使用 dos2unix 或类似工具删除它们,您可以设置 -v RS='\n\r'
.
发布问题时,请务必使其尽可能清晰、简单和简短,以便尽可能多的人有兴趣帮助您。
顺便说一句,cat input.txt | tr "\n" " "
是一个 UUOC,应该只是 tr "\n" " " < input.txt
这可能适合您 (GNU sed):
sed '/^chr/!{H;$!d};x;s/\n/\t/gp;d' file
如果一行不是以 chr
开头,则将其添加到保留 space 中,然后将其删除,除非它是最后一行。如果该行确实开始 chr
或者它是最后一行,则交换到保留 space 并用制表符替换所有换行符并打印出结果。
N.B。下一行的开头将在模式 space 中保持不变,成为新的保留 space.