使特定列中的数字在BASH中具有相同的长度

使特定列中的数字在BASH中具有相同的长度,bash,number-formatting,content-length,Bash,Number Formatting,Content Length,我需要第4列的所有数字都有4个字符 输入 期望输出 AGAP4 2061 0.534207 917.0 0 0 1 AGAP5 2061 0.536148 101.5 0 0 8 AGBL1 3201 0.514214 917.9 0 0 2 AGBL2 2709 0.444814 12.50 0 0 1 这不是您想要的,但提供了一致的宽度: awk '{$4=sprintf("%06.2f", $4)}1' input 产生: AGAP4 2061 0.534207 917.00 0 0

我需要第4列的所有数字都有4个字符

输入

期望输出

AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1

这不是您想要的,但提供了一致的宽度:

awk '{$4=sprintf("%06.2f", $4)}1' input
产生:

AGAP4 2061 0.534207 917.00 0 0 1
AGAP5 2061 0.536148 101.50 0 0 8
AGBL1 3201 0.514214 917.90 0 0 2
AGBL2 2709 0.444814 012.50 0 0 1

这不是您想要的,但提供了一致的宽度:

awk '{$4=sprintf("%06.2f", $4)}1' input
产生:

AGAP4 2061 0.534207 917.00 0 0 1
AGAP5 2061 0.536148 101.50 0 0 8
AGBL1 3201 0.514214 917.90 0 0 2
AGBL2 2709 0.444814 012.50 0 0 1

它相当不灵活,但处理您的具体问题:

awk 'length($4) == 4 { $4 = $4 "0" }1' file
如果第4个字段的长度为4个字符,则只需在其末尾添加一个0


如果要求更为复杂,例如长度变化可能超过一位数,那么您应该更新您的问题,以显示不同的输入。

这相当不灵活,但涉及您的具体问题:

awk 'length($4) == 4 { $4 = $4 "0" }1' file
如果第4个字段的长度为4个字符,则只需在其末尾添加一个0

如果要求更复杂,例如长度变化可能超过一位数,则应更新问题以显示不同的输入。

在bash(或POSIX shell)中,格式化的主要内置工具是
printf
。您可以读取每行的前4列和某个虚拟变量中的其余列,然后根据需要使用
printf
将这些列格式化为特定宽度进行打印:

#!/bin/bash

while read -r c1 c2 c3 c4 stuff; do 
    printf "%5s %4s %8s %5s %s\n" $c1 $c2 $c3 $c4 "$stuff"
done < "$1"

exit 0
输出

$ cat dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.5 0 0 1
$ bash fmtagap.sh dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814  12.5 0 0 1
$ bash fmtagap.sh dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1
bash中的
printf
采用与C中相同的格式字符串和格式说明符。您可以在
man3printf
中阅读有关格式化的所有内容。此外,bash还添加了一些功能,如
printf-v varname“fmt string”
来格式化结果并将其保存在
varname

格式字符串的一个限制是填充。虽然您可以
0
在左侧填充数字,但不能
0
在右侧填充数字。无论您是使用
%s
字符串转换还是
%5.1f
浮点转换,都仅限于左填充和字段宽度规格

当然,您可以在打印之前检查每个变量的长度,然后用这种方式在右侧填充
0
pad,但这就是您开始询问external shell实用程序是否可以为我这样做的地方。。。。但是,为了完整性:

#!/bin/bash

while read -r c1 c2 c3 c4 stuff; do 
    while [ ${#c4} -lt 5 ]; do
        c4="${c4}0"
    done 
    printf "%s %s %s %s %s\n" $c1 $c2 $c3 $c4 "$stuff"
done < "$1"

exit 0
在bash(或posixshell)中,用于格式化的主要内置工具是
printf
。您可以读取每行的前4列和某个虚拟变量中的其余列,然后根据需要使用
printf
将这些列格式化为特定宽度进行打印:

#!/bin/bash

while read -r c1 c2 c3 c4 stuff; do 
    printf "%5s %4s %8s %5s %s\n" $c1 $c2 $c3 $c4 "$stuff"
done < "$1"

exit 0
输出

$ cat dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.5 0 0 1
$ bash fmtagap.sh dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814  12.5 0 0 1
$ bash fmtagap.sh dat/agap.txt
AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1
bash中的
printf
采用与C中相同的格式字符串和格式说明符。您可以在
man3printf
中阅读有关格式化的所有内容。此外,bash还添加了一些功能,如
printf-v varname“fmt string”
来格式化结果并将其保存在
varname

格式字符串的一个限制是填充。虽然您可以
0
在左侧填充数字,但不能
0
在右侧填充数字。无论您是使用
%s
字符串转换还是
%5.1f
浮点转换,都仅限于左填充和字段宽度规格

当然,您可以在打印之前检查每个变量的长度,然后用这种方式在右侧填充
0
pad,但这就是您开始询问external shell实用程序是否可以为我这样做的地方。。。。但是,为了完整性:

#!/bin/bash

while read -r c1 c2 c3 c4 stuff; do 
    while [ ${#c4} -lt 5 ]; do
        c4="${c4}0"
    done 
    printf "%s %s %s %s %s\n" $c1 $c2 $c3 $c4 "$stuff"
done < "$1"

exit 0

Perl解决方案类似于@William的awk解决方案:

perl-lane'$F[3]=sprintf(“%06.2f”,$F[3]);打印联接“”@F'输入

AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1
-a
自动将每一行分割到
@F
数组中

输出:

AGAP4 2061 0.534207 917.00 0 0 1
AGAP5 2061 0.536148 101.50 0 0 8
AGBL1 3201 0.514214 917.90 0 0 2
AGBL2 2709 0.444814 012.50 0 0 1
使用
substr
生成所需的格式:

perl-lane'$F[3]=substr(sprintf(“%5.2f”,$F[3]),0,5;打印联接“”@F'输入

AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1

Perl解决方案类似于@William的awk解决方案:

perl-lane'$F[3]=sprintf(“%06.2f”,$F[3]);打印联接“”@F'输入

AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1
-a
自动将每一行分割到
@F
数组中

输出:

AGAP4 2061 0.534207 917.00 0 0 1
AGAP5 2061 0.536148 101.50 0 0 8
AGBL1 3201 0.514214 917.90 0 0 2
AGBL2 2709 0.444814 012.50 0 0 1
使用
substr
生成所需的格式:

perl-lane'$F[3]=substr(sprintf(“%5.2f”,$F[3]),0,5;打印联接“”@F'输入

AGAP4 2061 0.534207 917.0 0 0 1
AGAP5 2061 0.536148 101.5 0 0 8
AGBL1 3201 0.514214 917.9 0 0 2
AGBL2 2709 0.444814 12.50 0 0 1

谢谢@Willian,这真的很有帮助,也很容易应用!谢谢@Willian,这真的很有帮助,也很容易应用!谢谢你,大卫!真棒的解释!谢谢你,大卫!真棒的解释!