使用 awk 或 sed 重新排列具有空值的列
Rearrange column with empty values using awk or sed
我想重新排列 txt 文件的列,但是有空值,这会导致问题。例如:
测试文件:
Name ID Count Date Other
A 1 10 513 x
6 15 312 x
3 18 314 x
B 19 31 942 x
8 29 722 x
当我尝试时 $ more testfile |awk '{print "\t""\t""\t""\t"}'
它变成:
ID Name Count Date Other
1 A 10 513 x
15 6 312 x
18 3 314 x
19 B 31 942 x
29 8 722 x
这不是我想要的,请帮忙,我想要它
ID Name Count Date Other
1 A 10 513 x
15 6 312 x
18 3 314 x
19 B 31 942 x
29 8 722 x
此外,我不确定哪些列可能包含空值,并且列长度不固定,谢谢
awk
使用的最自然的模型是从白色-space 到非白色-space 并返回的过渡所定义的列。由于您的列本身可能是白色的-space,自然模型将不起作用。
但是,您可以恢复使用基于列 positions 而不是转换的模型,这意味着仅包含 spaces 的文件(制表符的存在将使事情复杂化):
Name ID Count Date Other
A 1 10 513 x
6 15 312 x
3 18 314 x
B 19 31 942 x
8 29 722 x
仍然可以重新排列,但不像基于转换的列那样简洁。
下面的 awk
脚本可以解决问题,交换 name
和 id
:
{
name = substr([=11=], 1,7);
id = substr([=11=], 9,7);
count = substr([=11=],17,7);
date = substr([=11=],25,7);
other = substr([=11=],33 );
print id" "name" "count" "date" "other;
}
如果原始文件名为pax.in
并且awk
脚本存储在pax.awk
中,命令awk -f pax.awk pax.in
将根据需要给出:
ID Name Count Date Other
1 A 10 513 x
6 15 312 x
3 18 314 x
19 B 31 942 x
8 29 722 x
请记住,我编写的脚本相对灵活,允许您很容易地更改列的顺序。如果你只想交换前两列,你可以使用:
awk '{print substr([=13=],9,8)substr([=13=],1,8)substr([=13=],17)}' qq.in
或稍短的(如果允许您使用其他工具):
sed -E 's/^(.{8})(.{8})//' qq.in
假设您的输入文件不是制表符分隔的并且您拥有(或可以获得)GNU awk 那么我建议:
$ awk -v FIELDWIDTHS="8 8 8 8 8" -v OFS='\t' '{
for (i=1;i<=NF;i++) {
gsub(/^\s+|\s+$/,"",$i)
}
t=; =; =t'
}1' file
ID Name Count Date Other
1 A 10 513 x
6 15 312 x
3 18 314 x
19 B 31 942 x
8 29 722 x
如果您的文件是制表符分隔的,那么您只需要:
awk 'BEGIN{FS=OFS="\t"} {t=; =; =t}1' file
awk 的另一种选择是使用字段数。如果你知道你的数据并且它只是第一列中的赤字,你可以试试这个。
awk -v OFS="\t" 'NF==4{=;=;=;=;=""} {print ,,,,}'
但是,输出将以制表符分隔,而不是固定长度格式。您可以使用 printf 和更改 OFS 实现相同的效果,但也许制表符分隔才是您真正需要的表格表示形式。
我想重新排列 txt 文件的列,但是有空值,这会导致问题。例如:
测试文件:
Name ID Count Date Other
A 1 10 513 x
6 15 312 x
3 18 314 x
B 19 31 942 x
8 29 722 x
当我尝试时 $ more testfile |awk '{print "\t""\t""\t""\t"}'
它变成:
ID Name Count Date Other
1 A 10 513 x
15 6 312 x
18 3 314 x
19 B 31 942 x
29 8 722 x
这不是我想要的,请帮忙,我想要它
ID Name Count Date Other
1 A 10 513 x
15 6 312 x
18 3 314 x
19 B 31 942 x
29 8 722 x
此外,我不确定哪些列可能包含空值,并且列长度不固定,谢谢
awk
使用的最自然的模型是从白色-space 到非白色-space 并返回的过渡所定义的列。由于您的列本身可能是白色的-space,自然模型将不起作用。
但是,您可以恢复使用基于列 positions 而不是转换的模型,这意味着仅包含 spaces 的文件(制表符的存在将使事情复杂化):
Name ID Count Date Other
A 1 10 513 x
6 15 312 x
3 18 314 x
B 19 31 942 x
8 29 722 x
仍然可以重新排列,但不像基于转换的列那样简洁。
下面的 awk
脚本可以解决问题,交换 name
和 id
:
{
name = substr([=11=], 1,7);
id = substr([=11=], 9,7);
count = substr([=11=],17,7);
date = substr([=11=],25,7);
other = substr([=11=],33 );
print id" "name" "count" "date" "other;
}
如果原始文件名为pax.in
并且awk
脚本存储在pax.awk
中,命令awk -f pax.awk pax.in
将根据需要给出:
ID Name Count Date Other
1 A 10 513 x
6 15 312 x
3 18 314 x
19 B 31 942 x
8 29 722 x
请记住,我编写的脚本相对灵活,允许您很容易地更改列的顺序。如果你只想交换前两列,你可以使用:
awk '{print substr([=13=],9,8)substr([=13=],1,8)substr([=13=],17)}' qq.in
或稍短的(如果允许您使用其他工具):
sed -E 's/^(.{8})(.{8})//' qq.in
假设您的输入文件不是制表符分隔的并且您拥有(或可以获得)GNU awk 那么我建议:
$ awk -v FIELDWIDTHS="8 8 8 8 8" -v OFS='\t' '{
for (i=1;i<=NF;i++) {
gsub(/^\s+|\s+$/,"",$i)
}
t=; =; =t'
}1' file
ID Name Count Date Other
1 A 10 513 x
6 15 312 x
3 18 314 x
19 B 31 942 x
8 29 722 x
如果您的文件是制表符分隔的,那么您只需要:
awk 'BEGIN{FS=OFS="\t"} {t=; =; =t}1' file
awk 的另一种选择是使用字段数。如果你知道你的数据并且它只是第一列中的赤字,你可以试试这个。
awk -v OFS="\t" 'NF==4{=;=;=;=;=""} {print ,,,,}'
但是,输出将以制表符分隔,而不是固定长度格式。您可以使用 printf 和更改 OFS 实现相同的效果,但也许制表符分隔才是您真正需要的表格表示形式。