My original answer was incorrect - xxd cannot accept either -p or -r with -b...
Given that the other answers are workable, and in the interest of "another way", how about the following:
Input
$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011
Output
$ hexdump -Cv < instructions.bin
00000000 00 00 00 13 02 d1 20 83 00 73 02 b3 00 73 04 33 |...... ..s...s.3|
00000010 00 73 64 b3 00 00 00 13 |.sd.....|
00000018
Bash pipeline:
cat instructions.txt \
| tr -d $'\n' \
| while read -N 4 nibble; do
printf '%x' "$((2#${nibble}))"; \
done \
| xxd -r -p \
> instructions.bin
cat - unnecessary, but used for clarity
tr -d $'\n' - remove all newlines from the input
read -N 4 nibble - read exactly 4× characters into the nibble variable
printf '%x' "$((2#${nibble}))" convert the nibble from binary to 1× hex character
$((2#...)) - convert the given value from base 2 (binary) to base 10 (decimal)
printf '%x' - format the given value from base 10 (decimal) to base 16 (hexadecimal)
xxd -r -p - reverse (-r) a plain dump (-p) - from hexadecimal to raw binary
Python:
python << EOF > instructions.bin
d = '$(cat instructions.txt | tr -d $'\n')'
print(''.join([chr(int(d[i:i+8],2)) for i in range(0, len(d), 8)]))
EOF
- An unquoted heredoc (
<< EOF) is used to get content into the Python code
- This is not efficient if the input becomes large
cat and tr - used to get a clean (one-line) input
range(0, len(d), 8) - get a list of numbers from 0 to the end of the string d, stepping 8× characters at a time.
chr(int(d[i:i+8],2)) - convert the current slice (d[i:i+8]) from binary to decimal (int(..., 2)), and then to a raw character (chr(...))
[ x for y in z] - list comprehension
''.join(...) - convert the list of characters into a single string
print(...) - print it