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

Make Numbers in a specific column to have the same Length in BASH

我需要第 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.5 0 0 1

期望的输出

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 '{=sprintf("%06.2f", )}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 {  =  "0" }1' file

它所做的只是在第 4 个字段的末尾添加一个 0,如果它有 4 个字符长。

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

在 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 < ""

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 中的

printf 采用与 C 中相同的格式字符串和格式说明符。您可以阅读 man 3 printf 中的格式化可以做的所有事情。另外bash加了几个,比如printf -v varname "fmt string"格式化结果保存在varname.

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

当然,您可以在打印前检查每个变量的长度,然后 0 以这种方式在右侧填充,但这就是您开始询问是否可以使用外部 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 < ""

exit 0

输出

$ 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

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

perl -lane '$F[3] = sprintf("%06.2f", $F[3]); print join " ",@F' input

-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); print join " ",@F' input

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