Note that, if it's about padding with 0 bytes to align to some boundary, you can use dd with conv=sync for that.
$ echo test | dd bs=128 iflag=fullblock conv=sync | hexdump -Cv
0+1 records in
1+0 records out
128 bytes copied, 5.9459e-05 s, 2.2 MB/s
00000000 74 65 73 74 0a 00 00 00 00 00 00 00 00 00 00 00 |test............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000080
(iflag=fullblock is a GNU extension¹, but is only needed for pipe inputs or more generally when there could be short reads, not for regular files; with GNU dd, you can also add status=none to remove the transfer information).
Or you can use truncate on an already existing file to a larger size, for the end to be filled with NULs (not taking any more space on disk):
$ echo test > file
$ truncate -s 1M file
$ hexdump -C file
00000000 74 65 73 74 0a 00 00 00 00 00 00 00 00 00 00 00 |test............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00100000
Or the same with fallocate -l in place of truncate -s to allocate the disk space.
Note that among the shells that have copied zsh's {x..y}, bash is the only one where {1..$n} doesn't work, so here, you could also switch to one of those shells (zsh, ksh93, yash -o brace-expand).
In zsh:
$ hex=00; n=100; printf "\x$hex%.0s" {1..$n} | hexdump -Cv
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 |....|
00000064
zsh also has padding operators and (contrary to bash) can store arbitrary bytes in its variable:
$ string=test n=128 pad=$'\0'; printf %s ${(pr[n][$pad])string} | hexdump -Cv
00000000 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00 |test............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000080
(beware, padding is based on number of characters, use set +o multibyte for it to be byte-wise in locales where characters can be made of more than one byte).
¹ Since added to the 2024 edition of the POSIX standard, but currently with an unfortunate typo as they have iflags=fullblock instead of iflag=fullblock, typo copied from the request to add that GNU extension to the standard.
>>append was moved to after thedone. That would only open the output file for append once, instead of 65515 times.