我有一个包含一列数据的文件(即每行一个数据值)。我将这些数据解释为多个数据套;
数据集由一行或多NA
行分隔。请注意,数据集的长度不同。我想将其转换为多列格式,其中每个数据集都位于一列中(与它们在输入文件中出现的顺序相同)。
例如,我有以下文件(实际上,该文件包含更多数据):
NA
4
3
5
7
8
3
NA
NA
NA
3
4
5
2
NA
2
7
4
6
9
NA
我的预期输出如下:
4 3 2
3 4 7
5 5 4
7 2 6
8 . 9
3
8 和 9 之间的点并不是真正需要的,但也可以用空格代替。
答案1
您可以awk
将每组数据(其中的数据位于NA
行之间)分割成单独的文件并跳过NA
行,然后将paste
它们放在一起。
awk '/^NA$/ && !NA{N++; NA=1; next} !/^NA$/{print >"file"N; NA=0}
END{system("paste file*")}' inile.txt
该NA
标志用于按顺序创建文件,我们可以在下面使用。
awk '/^NA$/{N++; next} !/^NA$/{print >"file"N}
END{system("paste file*")}' inile.txt
输出是:
4 3 2
3 4 7
5 5 4
7 2 6
8 9
3
答案2
该输出格式对我来说没有意义。我认为这根本不实用。
无论如何,只需每行写入它,然后转置(或者更好,将其保留在每行):
tr '\n' ' ' < example | tr 'N' '\n' | sed 's/^A //; /^$/d'
给出
4 3 5 7 8 3
3 4 5 2
2 7 4 6 9
答案3
在外壳中转换是一件痛苦的事情。这是 Perl 的简短答案,需要数组::转置::参差不齐来自 CPAN
perl -MArray::Transpose::Ragged=transpose_ragged -lnE '
if (/NA/) { $n++; next } # next row
push @{$data[$n]}, $_; # creating the 2D matrix of data
} END {
say join "\t", @$_ for transpose_ragged [grep {defined} @data];
' file
这是另一种方法:之前的管道gawk
本质上与 @n.caillou 的答案相同,awk 代码进行转置
paste -sd " " file | sed 's/NA/\n/g' | sed '/^ *$/d' | gawk '
{
for (i=1; i<=NF; i++) data[FNR][i] = $i
if (NF > max) max = NF
}
END {
for (i=1; i<=max; i++) {
for (j=1; j<=NR; j++) printf "%s\t", data[j][i]
print ""
}
}
'
使用 GNU awk 处理多维数组
答案4
这GNU 数据混合需要 1.1.1 版本。在 1.0.7 版本中它无法正常工作。
#!/bin/bash
tr '\n' ' ' < input.txt |
sed 's/\s*NA\s*/\n/g;' |
sed '/^$/d' |
datamash --no-strict --filler="." -W -t' ' transpose
解释
tr '\n' ' ' < input.txt
- 将所有换行符替换为空格。换句话说,将所有行连接到一行。sed 's/\s*NA\s*/\n/g;'
- 将所有“NA”和相邻空格替换为换行符。也就是说,它将大行分成几行,每一行都是未来的列,水平书写。sed '/^$/d'
- 删除所有空行。datamash --no-strict --filler="." -W -t' ' transpose
--no-strict
- 允许具有不同数量字段的行--filler="."
- 用点填充缺失值。可以将其更改为空间。-W
- 使用空格(一个或多个空格和/或制表符)作为输入字段分隔符。-t' '
- 使用空格而不是制表符作为输出字段分隔符。transpose
- 将行转换为列。
输入
NA
4
3
5
7
8
3
NA
NA
NA
3
4
5
2
NA
2
7
4
6
9
NA
输出
4 3 2
3 4 7
5 5 4
7 2 6
8 . 9
3 . .