如何将多行转换为固定列长度

时间:2015-01-12 13:16:07

标签: unix awk sed

要将行转换为制表符分隔,很容易

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)

4 个答案:

答案 0 :(得分:1)

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可以)

答案 1 :(得分:1)

这是使用4列而不是44列的正确方法:

$ cat file
chr10_1000103_+
0.932203
0.956522
1
chr10_1000104_-
0.952381
1
1

$ awk '{printf "%s%s", $0, (NR%4?"\t":"\n")}' file
chr10_1000103_+ 0.932203        0.956522        1
chr10_1000104_- 0.952381        1       1

只需更改4到44即可获得实际输入。

如果你在输出中看到control-Ms,那是因为它们存在于你的输入中,所以在运行工具之前使用dos2unix或类似的删除它们,或者使用GNU awk你可以设置-v RS='\n\r'

在发布问题时,尽可能使其变得清晰,简单和简洁非常重要,以便尽可能多的人有兴趣帮助您。

BTW,cat input.txt | tr "\n" " "是UUOC,应该是tr "\n" " " < input.txt

答案 2 :(得分:0)

不是最佳解决方案,但应该有效:

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", $1 } NR%44==0{ print "" }' < input.txt

您可能希望使用| sed 's/\t$//'删除尾随制表符或使awk脚本更复杂。

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed '/^chr/!{H;$!d};x;s/\n/\t/gp;d' file

如果一行不以chr开头,则将其附加到保留空间,然后将其删除,除非它是最后一行。如果该行确实开始chr或它是最后一行,则交换到保留空间并按标签替换所有换行并打印出结果。

N.B。在模式空间中,下一行的开头将保持不变,这将成为新的保留空间。