2017-05-31 51 views
1

我有这种奇怪的情况,我得到了一系列表示二进制数据的HEX值。有趣的是,他们是偶尔长度不同,如:BASH:基于最长的字符串填充一系列HEX值

40000001AA 
0000000100 
A0000001 
000001 
20000001B0 
40040001B0 

我想追加对最终0以使它们都按照最长项的长度相同。所以,在上面的例子中,我有四个长度为10个字符的条目,以'\ n'结尾,还有一些短条目(在实际数据中,我有约1k条短条目的200k条目)。我想要做的是找出文件中最长的字符串,然后通过并填充短的字符串;但是,我一直无法弄清楚。任何建议,将不胜感激。

+1

顺便说一句,如果您将0附加到数据中,则会更改值。您可能需要考虑_prepending_ 0。 –

+0

@MatthewBurke是的,由于一个怪癖,他们的数据是相反的,所以最终实际上是开始。

回答

1

一般而言到零垫从两侧的任一个或一个字符串(使用5如例如所需的字段宽度):

$ echo '17' | awk '{printf "%0*s\n", 5, $0}' 
00017 

$ echo '17' | awk '{printf "%s%0*s\n", $0, 5-length(), ""}' 
17000 

$ echo '17' | awk '{w=int((5+length())/2); printf "%0*s%0*s\n", w, $0, 5-w, ""}' 
01700 

$ echo '17' | awk '{w=int((5+length()+1)/2); printf "%0*s%0*s\n", w, $0, 5-w, ""}' 
00170 

所以对于你的例子:

$ awk '{cur=length()} NR==FNR{max=(cur>max?cur:max);next} {printf "%s%0*s\n", $0, max-cur, ""}' file file 
40000001AA 
0000000100 
A000000100 
0000010000 
20000001B0 
40040001B0 
+1

这真的很好。我使用的是BSD系统,因此大多数其他解决方案都不能正常工作,因为它们都是GNU特有的。 –

1

让我们假设你在文件中这样的值:

file=/tmp/hex.txt 

找出最长号码的长度:

longest=$(wc -L < $file) 

现在在文件中的每个数与零证明它

while read number; do 
    printf "%-${longest}s\n" $number | sed 's/ /0/g' 
done < $file 

这将打印脚本到标准输出:

40000001AA 
0000000100 
A000000100 
0000010000 
20000001B0 
40040001B0 
+0

请参阅[为什么要使用shell循环处理文本被认为是坏行为](https://unix.stackexchange.com/questions/169716/why-is-using-a对于这个答案的一些问题,但并不是全部,这个问题的解决方法就是从shell-loop-to-process-text-considered-bad-practice)。只需使用awk。为了清晰,高效,鲁棒性,可移植性以及大多数其他所需的软件属性。 –

2

当您使用Bash时,您很有可能还会使用其他GNU 工具。在这种情况下,wc可以使用-L选项轻松告诉您文件最大行长度的 。例如:

$ wc -L /tmp/HEX 
10 /tmp/HEX 

填充可以做这样的:

$ while read i; do echo $(echo "$i"0000000000 | head -c 10); done < /tmp/HEX 
40000001AA 
0000000100 
A000000100 
0000010000 
20000001B0 
40040001B0 

一个班轮:

while read i; do eval printf "$i%.s0" {1..$(wc -L /tmp/HEX | cut -d ' ' -f1)} | head -c $(wc -L /tmp/HEX | cut -d ' ' -f1); echo; done < /tmp/HEX 
3

使用标准的两通AWK:

awk 'NR==FNR{if (len < length()) len=length(); next} 
    {s = sprintf("%-*s", len, $0); gsub(/ /, "0", s); print s}' file file 

40000001AA 
0000000100 
A000000100 
0000010000 
20000001B0 
40040001B0 

或者使用gnu wcawk

awk -v len="$(wc -L < file)" ' 
    {s = sprintf("%-*s", len, $0); gsub(/ /, "0", s); print s}' file 

40000001AA 
0000000100 
A000000100 
0000010000 
20000001B0 
40040001B0 
+1

谢谢埃德,这是一个非常好的建议,一如既往:) – anubhava