我在 Linux 机器上有一个包含两列的文本文件:
- 第1列 = id_no(大部分为5位,有的为6位);
- 第 2 列 = Genetic_markers(全部长度为 50674 位);
12345 0102010205
54322 2221110051
123456 1122011510
我想将文件更改为如下所示:
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
如何更改第一列,使其向右对齐(如数字所示)?
有人可以帮我用最可靠的方法来更改第二列数字之间的空格吗?请解释代码的元素及其作用。
谢谢
答案1
和perl
:
$ perl -lane 'printf "%6s %s\n", $F[0], join " ", split "", $F[1]' <your-file
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
使用-lane
(-n
一次读取输入一条记录,并-e
使用 中的记录运行表达式$_
,-a
因为a
wk 将行拆分为@F
字段,从记录中-l
删除ine 分隔符),其行为类似于。l
perl
awk
在这里,我们使用printf
空格将第一个字段左填充到 6 的长度,然后用空格将join
第二个字段拆分为其字符组成部分。
答案2
为了右对齐,您需要找到文件中最长数字的长度,或者只选择一个大数字并使用它。例如,您可以填充 10 个空格:
$ printf '%d\n' 123
123
$ printf '%10d\n' 123
123
如果这种方法足够好,您可以执行以下操作:
$ awk '{ gsub(/./," &",$2); printf "%10d%s\n",$1,$2}' file
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
这里只发生了两件事:
gsub(/./," &",$2);
: 这gsub
(G全局的子.
stitution) 函数将用您提供的任何替换项替换您给它的正则表达式的所有匹配项(在这里,我们只给它一个含义“任何字符”)。具有&
特殊含义,表示“正则表达式匹配的任何内容”,因此&
作为替换给出的效果是在每个字符之前插入一个空格。最后一个参数是输入,这里我们给它第二个字段$2
。printf "%10d %s\n",$1,$2
:我们用来printf
打印格式化字符串。%10d
意思是“打印我给你的数字并用10个空格填充”,%s
意思是“打印这个字符串”。因此,我们告诉它打印第一个字段填充了 10 个空格,然后打印已被 修改的第二个字段gsub
。
如果只需要填充最小值,则需要读取文件两次。首先获取最长的第一个字段的长度:
$ awk -v max=0 '{ if(length($1) > max){ max=length($1) }} END{print max}' file
6
有了这个,你就可以更具体:
$ awk '{ k=gsub(/./," &",$2); printf "%6d%s\n",$1,$2}' file
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
答案3
使用anyawk
和GNU column
(对于-R
):
$ awk '{gsub(/./," &",$2)} 1' file | column -tR1
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
-o' '
如果您真的关心字段之间的空格,请添加:
$ awk '{gsub(/./," &",$2)} 1' file | column -o' ' -t -R1
12345 0 1 0 2 0 1 0 2 0 5
54322 2 2 2 1 1 1 0 0 5 1
123456 1 1 2 2 0 1 1 5 1 0
答案4
使用乐(以前称为 Perl_6)
~$ raku -ne '.split(" ") andthen put sprintf("%6d", .[0]), .[1].comb;' file
#OR
~$ raku -ne '.words andthen put sprintf("%6d", .[0]), .[1].comb;' file
Raku 是 Perl 家族的一种编程语言。上面使用了 Raku 的-ne
非自动打印逐行标志。默认情况下,该-n
标志会删除行终点的分隔符。然后,您可以print
省略尾随换行符(默认情况下),或者put
,这会添加尾随换行符(想象一下put
代表使用终止符打印)。
在第一个答案中,该行明确位于.split
单空格( 的缩写$_.split
)上。在第二个答案中,Raku 的.words
例程用于按空格进行分割。此后,连接andthen
重新加载$_
,以便可以格式化每列以进行输出。第一列(即.[0]
)使用格式化,sprintf
而第二列(即.[1]
)被comb
编辑为单个字符并返回。
注意:如果“ID”确实是(十进制)无符号整数,那么在内部sprintf
您可以使用u
代替d
,如 中所示sprintf("%6u", …)
。
输入示例:
12345 0102010205
54322 2221110051
123456 1122011510
示例输出:
123450 1 0 2 0 1 0 2 0 5
543222 2 2 1 1 1 0 0 5 1
1234561 1 2 2 0 1 1 5 1 0
注意:为了避免在文件可能包含空行时引发错误,您可以添加if
条件来删除空行:
~$ raku -ne 'if .chars { .words andthen put sprintf("%6d", .[0]), .[1].comb};' file
#OR
~$ raku -ne 'if $_ .= words {put sprintf("%6d", .[0]), .[1].comb};' file
要保留空行,您可以使用 Raku 的三元操作员:
~$ raku -ne '.chars ?? ( .split(" ") andthen put sprintf( "%6d", .[0]), .[1].comb) !! "".put;' file
#OR
~$ raku -ne '$_ .= split(" ", :skip-empty) ?? (put sprintf( "%6d", .[0]), .[1].comb) !! "".put;' file
https://docs.raku.org/routine/sprintf
https://docs.raku.org/routine/%3F%3F%20%21%21
https://raku.org