TL;DR
With no scp/sftp, turn the binary into ASCII text, push it through the terminal, and rebuild it:
| |
Always verify with a hash on both ends (sha256sum file.bin). If it doesn’t match, the paste dropped bytes.
When you need this
Sometimes all you have is a shell: a Telnet session to an old box, a serial console, an ssh into a jail with no scp, a minimal container with no network tools, or a KVM/IPMI where all you can do is type. No file transfer — but you can write and read text.
The trick: any file — even a binary — can be represented as printable ASCII. You encode it at the source, copy the text through the terminal, and decode it at the destination. Two tools do this: base64 (modern, everywhere) and uuencode (classic, from the UUCP and Usenet days).
Option 1: base64 (recommended)
base64 ships with coreutils, so it’s on virtually any modern Linux/BSD/macOS.
At the source — encode and print the text:
| |
For a large file, send it to a .txt and open it, or print it as a single unwrapped line:
| |
Copy the whole output (it’s printable text, safe to paste).
At the destination — paste the text and decode:
| |
Ctrl-D signals end of input (EOF) and base64 -d writes the reconstructed binary.
On macOS/BSD the single-line flag isn’t
-w0. Usebase64 -i file.binto encode andbase64 -D(capital D) to decode. When in doubt,base64 --help.
Option 2: uuencode / uudecode (classic)
uuencode/uudecode ship in the sharutils package. It’s what people used to mail binaries over email and Usenet before MIME. Handy on an old system that already has it and lacks base64.
| |
At the source — the second argument is the name the file will get on decode:
| |
It prints a block that starts with begin 644 file.bin and ends with end. Copy all of it, including those two lines.
At the destination — paste the block and decode:
| |
uudecode reads the name from the block itself (begin 644 file.bin) and creates file.bin on its own. You don’t pass an output name.
Always verify with a hash
Pasting long text into a terminal is fragile: a truncated buffer, a dropped character, a wrap that injects a space. Confirm the file arrived intact:
| |
If the hashes differ, the paste got corrupted. Retry, or split the file (below).
Compress before you encode
base64 inflates the file by ~33%. Compress it first and there’s less text to paste — and you get to bundle a whole directory into one file. Compress, encode, and on the other side reverse the order: decode, decompress.
A single file with gzip (or bzip2 / xz, better ratio, slower):
| |
A whole directory with tar (pack + compress + encode):
| |
Verify the tar.gz with sha256sum (not the loose contents) on both ends: comparing one file is easier than comparing a directory.
Large files: split them
Pasting megabytes of text into a terminal is asking for trouble. If it’s still large after compressing, split before encoding:
| |
What each piece does
| Command | What it does |
|---|---|
base64 file | Binary → ASCII text (76-char lines by default) |
base64 -w0 file | Same, but a single line (GNU); handy to paste in one go |
base64 -d | base64 text → binary (reads stdin until EOF) |
uuencode in out | Binary → begin…end block; out = name on decode |
uudecode | begin…end block → file (takes the name from the block) |
gzip -c / -d | Compress / decompress to stdout (also bzip2, xz) |
tar czf - dir/ | Pack and compress a directory to stdout (z=gzip, j=bzip2, J=xz) |
tar xzf - | Extract a directory from stdin |
split -b | Chop a file into fixed-size pieces |
sha256sum | Hash to verify end-to-end integrity |
Traps
- Always verify with a hash. It’s the only safeguard against a truncated paste. Without it, you think you copied the file and you’ve got garbage.
- Size grows ~33–35%. base64 adds ~33%, uuencode ~35%. A 3 MB binary becomes ~4 MB of text to type/paste. That’s what
splitis for. - Different flags on macOS/BSD vs GNU.
-w0/-dare GNU; on macOS it’s-i/-D. Don’t assume. - Watch your terminal client’s auto-wrap. Some Telnet/serial clients insert breaks or cut long lines. If it fails, use base64 with wrap (drop
-w0) and smaller blocks. - Telnet is cleartext. Anything sensitive sent over Telnet travels unencrypted. Use it only on local/serial consoles or trusted networks; for everything else, SSH.
- Not for TBs. This is for rescuing a file when there’s no other way, not for moving volumes. If you can use
scp/rsync/sftp, use them.