使特定列中的数字在BASH中具有相同的长度
我需要第4列的所有数字都有4个字符 输入 期望输出使特定列中的数字在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
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,这真的很有帮助,也很容易应用!谢谢你,大卫!真棒的解释!谢谢你,大卫!真棒的解释!