Shell

使用 NULL 將標準輸入填充到所需長度的最佳方法

  • July 21, 2021

我有以下要求。我有一個輸入流,我需要將其截斷為某個固定長度的字節。我事先不知道輸入流的長度。如果流的長度小於設置的長度,我想用零字節填充它。我嘗試使用truncate,但顯然它只能處理不使用標準輸入的文件。

例如,假設我們的輸入流 (stdin) 是TEST並且我們希望達到 10 字節的長度。那麼輸出流(stdout)應該是TEST\x00\x00\x00\x00\x00.

為了澄清這個例子是用小字元串完成的,但結果應該在大流(兆字節到千兆字節)上表現良好。我使用的容器目前也是基於 Ubuntu 的。

使用 GNU dd

$ printf %s test | dd iflag=fullblock bs=10 status=none conv=sync count=1 | hexdump -C
00000000  74 65 73 74 00 00 00 00  00 00                    |test......|
0000000a

使用zsh, 使用其r右填充(和截斷)參數擴展標誌(以及p用於轉義序列的標誌,例如\0在填充字元串中擴展):

$ string=test
$ printf %s ${(pr[10][\0])string} | hexdump -C
00000000  74 65 73 74 00 00 00 00  00 00                    |test......|
0000000a

雖然請注意,它填充到 10 個字元,而不是 10 個字節。您可以關閉該multibyte選項以更改該選項 ( set +o multibyte)。

$ string=tést
$ printf %s ${(pr[10][\0])string} | hexdump -C
00000000  74 c3 a9 73 74 00 00 00  00 00 00                 |t..st......|
0000000b
$ printf %s ${(pr[10][\0])string} | wc -mc
    10      11
$ set +o multibyte
$ printf %s ${(bpr[10][\0])string} | hexdump -C
00000000  74 c3 a9 73 74 00 00 00  00 00                    |t..st.....|
0000000a
$ printf %s ${(bpr[10][\0])string} | wc -mc
     9      10

這些解決方案不能很好地擴展到大於系統上 RAM 量的大小。

對於大尺寸,正如@ilkkachu 在評論中所建議的那樣,

{ printf %s test; cat /dev/zero; } | head -c 1000000000

會更有效(head -c不是標準的,但很常見,並且比dd bs=1一次讀取和寫入一個字節的效率要高得多)。

如果輸出到文件,您還可以使用資源限制進行截斷:

(
 ulimit -f 1048576 # KiB
 printf %s test
 cat /dev/zero
) > file

引用自:https://unix.stackexchange.com/questions/659321