To open a bin file in Linux, start with the bytes rather than the extension. I ask the file command to name the shape, because the same three letters cover a self-extracting installer, a disk image, a compiled program, and a heap of raw data.
Each shape has its own two-command lane below, and I kept every output exactly as the command returned it.
The extension does not say what the file is
The .bin extension is a label that was chosen at download time, and nothing in it constrains what the bytes are. The four samples below are all .bin files, and file printed a different first line for each one.

| What file prints | What the file is | The command that follows |
|---|---|---|
| POSIX shell script executable, self-executable archive, Makeself 2.5.0 | Self-extracting installer | chmod +x, then run it |
| DOS/MBR boot sector, FAT (32 bit) | Disk image | Mount it through a loop device |
| ELF 64-bit LSB executable, x86-64 | Compiled program | Run it, if the CPU matches |
| data | Raw bytes | xxd or strings, and nothing runs |

Where a file ends up matters too, because system binaries live in /usr/bin while locally installed ones live in /usr/local/bin. The Linux file system layout explains why those two paths sit on different shelves.
Files arrive with this extension from three directions. Software vendors ship their installers as .bin, disc and SD-card images carry it, and firmware for embedded hardware is a header plus a payload with no filesystem in sight.
The Oracle JDK for Linux is the installer people meet first, and its install page is the chmod +x sequence written by the vendor itself rather than by a tutorial.
The /usr/bin directory is a different sense of the same word, and it holds programs the system installed rather than anything you downloaded. Keeping those two ideas apart answers the question people ask first when a .bin file refuses to run.
What you need before the first command
The three commands below tell you what you are holding, and none of them runs the file. Open a terminal in the directory that holds your download, then read the output before you pick a lane.
I classify the file before touching its permissions, because a mount and a chmod are not interchangeable, and the wrong one wastes a step.
file myfile.bin
head -n 6 myfile.bin
ls -l myfile.bin
The first line classifies the file, the second shows the header script an installer carries, and the third shows whether the execute bit is set. I keep all three in one pass, because each result changes what the next command should be.
What file reads is the first bytes of the file rather than its name, so dumping the first bytes of each one shows where the classification comes from.
$ xxd -l 8 installer.bin
00000000: 2321 2f62 696e 2f73 #!/bin/s
$ xxd -l 8 hello.bin
00000000: 7f45 4c46 0201 0100 .ELF....
$ xxd -l 8 firmware.bin
00000000: eb58 906d 6b66 732e .X.mkfs.
$ xxd -l 8 data.bin
00000000: 7444 7773 b3f4 aed5 tDws....
A shebang, the ELF marker, and the jump instruction that starts a boot sector are between them the whole basis for the first line file prints.

A .bin file you downloaded is also a file you have not verified yet. Compare the checksum the vendor publishes against a sha256sum of your copy, and stop there when the two disagree.
If the download itself is what keeps failing, pulling the file and its checksum list with wget in the same pass is the habit worth keeping.
A self-extracting archive runs whatever its author put inside it, and the extension carries no signature, so the published checksum and the vendor page are the two things worth confirming before the first command.
Opening a .bin file that is a self-extracting installer
When file reports a shell script, you are holding a Makeself archive: a header script with a compressed payload appended to the end of it. The header is what runs.
Give it the execute bit
A downloaded file lands with read and write permission only, so bash refuses to run it.
chmod +x downloaded.bin

The chmod command is the only permission change needed here, and it needs no sudo while the file sits inside your home directory.
Check it, then run it
Makeself archives carry their own checksum, so the payload can be verified before anything executes.
$ ./installer.bin --check
Verifying archive integrity... MD5 checksums are OK. All good.
That check read the embedded metadata and reported the archived checksums as intact. Running the archive performs the same verification and then executes the payload script inside it.
I checked the archive before running it. The check costs one command, while the payload runs with my own permissions and my own files.
The header knows where the payload starts because it records its own length in a variable and skips those lines with dd. Each file inside the payload carries its own MD5, and the archive is unpacked only after every one of them matches.
$ ./broken.bin --check
Verifying archive integrity... Error in MD5 checksums: 1f4e7e5f773d8667e880caaedab464f3 is different from 3d088071c61ef549886a60b611b36b15
I wrote a single byte over the archive to produce that copy, and the check rejected it before anything unpacked. A download that stopped early fails the same way, which makes this the cheapest test you can run on an installer you have never seen before.
$ ./installer.bin
Verifying archive integrity... MD5 checksums are OK. All good.
Uncompressing Demo app installer
Hello from the payload

An installer that writes outside your home directory needs sudo, and the sudo command covers what that changes and what it does not.
Extract it without installing
Running an installer you have not inspected is a choice rather than a requirement. Makeself can unpack the payload and leave it on disk for you to read first.
The archive also describes itself before it extracts anything, which is how you find out what it intends to do.
$ ./installer.bin --info
Identification: Demo app installer
Target directory: payload
Uncompressed size: 12 KB
Compression: gzip
Built with Makeself version 2.5.0
Script run after extraction:
./hello.sh
$ ./installer.bin --noexec --target app
Creating directory app
Uncompressing Demo app installer
$ ls app
asset.dat hello.sh release.txt
The noexec flag stops the payload from running, and target names the directory it lands in. The extracted files are ordinary files, so anything you want to inspect is now in front of you.
| Flag | What it does |
|---|---|
| –check | Verifies the embedded checksum and extracts nothing |
| –info | Prints the label, target directory, size, compression and build command |
| –list | Lists the files inside the payload without extracting them |
| –noexec | Extracts the files and does not run the embedded script |
| –target dir | Extracts into the named directory instead of a temporary one |
Those flags exist because the header is an ordinary shell script that parses its own arguments, which is also why a damaged download can be caught before it runs.
Opening a .bin file that is a disk image
When file reports a boot sector or a filesystem instead of a program, the bytes are a whole disk written into a file. Nothing in it is executable, and the command that opens it is a mount.

Mount a flat image
An image with its filesystem at the start mounts in a single command, and read-only is the safe default.
sudo mount -o loop,ro firmware.bin /mnt/bin
ls /mnt/bin
sudo umount /mnt/bin

The loop option attaches the file to a loop device and mounts that device, which is why the mount is silent and the listing is the confirmation that counts. Mounting a filesystem from another system goes through the same step.
A loop device is a block device backed by a file, so the kernel treats the image as a disk that happens to live inside your home directory. That is also why unmounting matters: the loop device stays attached until the filesystem is released.
I mount these read-only by default, because nothing here needs to write to the image.
Mount an image with a partition table
SD card images and firmware files carry a partition table, and there the filesystem starts partway into the file instead of at byte zero.
$ file sd-image.bin
sd-image.bin: DOS/MBR boot sector; partition 1 : ID=0xc, start-CHS (0x10,0,1), end-CHS (0x3ff,3,32), startsector 2048, 219136 sectors
Mounting that file directly fails, because mount looks for a filesystem exactly where it finds a partition table instead.
$ sudo mount -t vfat sd-image.bin /mnt/bin
mount: /mnt/bin: wrong fs type, bad option, bad superblock on /dev/loop23, missing codepage or helper program, or other error.

Ask the kernel to read the partition table, then mount the partition rather than the whole file. The loop device number in my output will differ from yours, so read it from losetup instead of copying it.
$ sudo losetup -P --show -f sd-image.bin
/dev/loop23
$ sudo mount -o ro /dev/loop23p1 /mnt/bin
$ ls /mnt/bin
EFI
$ sudo umount /mnt/bin
$ sudo losetup -d /dev/loop23
The partscan flag creates one device per partition, which is where the p1 suffix comes from, and reading the partition table is what tells you how many suffixes to expect.
There is a second route that skips losetup, and it starts with the same starting sector. On a disk with 512-byte sectors, sector 2048 is a fixed byte offset.
sudo mount -o loop,ro,offset=$((2048*512)) sd-image.bin /mnt/bin
ls /mnt/bin
The arithmetic is where this goes wrong, because an offset that is one sector out produces the same wrong fs type error you were trying to avoid.
Either route ends with the same check. The partition appears under the loop device in lsblk, and that child entry is what confirms the scan found a filesystem to mount.
Opening a .bin file that is just data
Some .bin files are neither programs nor filesystems, and file says so in a single word. There is no opener for those, because there is nothing to open, and reading the first lines tells me whether there is anything to open at all.
$ xxd data.bin | head -4
00000000: 7444 7773 b3f4 aed5 866f d06f 50db 1b78 tDws.....o.oP..x
00000010: 3e54 418c 348e 4658 f37f 93bd 2e15 c2fb >TA.4.FX........
00000020: 5983 3038 88a4 3f8a 1877 1a16 7d6a 16d1 Y.08..?..w..}j..
00000030: 29e0 a89b 76e3 74c4 30de 85f9 bf24 f389 )...v.t$....$..
$ strings data.bin | head -5
tDws
x>TA
2$AKNN
u2D_
fjW;
A hex dump shows you where the structure is and a string scan shows you whether any text survived, and between them they answer the question a text editor cannot. When the answer is still nothing readable, you are holding an opaque blob and the tool that produced it is the only thing that can use it.
$ od -c data.bin | head -3
0000000 t D w s 263 364 256 325 206 o 320 o P 333 033 x
0000020 > T A 214 4 216 F X 363 177 223 275 . 025 302 373
0000040 Y 203 0 8 210 244 ? 212 030 w 032 026 } j 026 321
$ hexdump -C data.bin | head -3
00000000 74 44 77 73 b3 f4 ae d5 86 6f d0 6f 50 db 1b 78 |tDws.....o.oP..x|
00000010 3e 54 41 8c 34 8e 46 58 f3 7f 93 bd 2e 15 c2 fb |>TA.4.FX........|
00000020 59 83 30 38 88 a4 3f 8a 18 77 1a 16 7d 6a 16 d1 |Y.08..?..w..}j..|
Both of those print the same bytes in different layouts, and either is enough when all you need is a look at where the shape of the data changes.
An encrypted archive and a compressed package land in this lane as well. When the dump starts with a recognizable magic number, the format it belongs to is the thing to look up, and the tool that wrote it is the thing that reads it.
The four errors that tell you the lane is wrong
Each lane fails in a way that names its own mistake, and the message is faster to read than the guide is to re-read. These four came back from the sample files above.
| Message | Exit code | What it means | What to do next |
|---|---|---|---|
| bash: ./file.bin: Permission denied | exit code 126 | The execute bit is not set | chmod +x file.bin |
| bash: ./file.bin: cannot execute binary file: Exec format error | exit code 126 | The program was built for a different CPU | Fetch the build for your architecture |
| mount: wrong fs type, bad option, bad superblock | exit code 32 | Mount aimed at the partition table | losetup -P, then mount the p1 device |
| Error in MD5 checksums: 1f4e7e5f… is different from 3d088071… | exit code 2 | The archive changed after it was built | Download it again and compare the published checksum |
Both errors exit with code 126 and they mean opposite things. Permission denied says the file is a program you have not unlocked, and Exec format error says the file is a program your CPU cannot run.
Firmware blobs fail in a lane of their own. file calls them data, no mount succeeds, and the flashing tool that produced the file is the only program that reads it back.
Read the header, then pick the lane
A single line settles which of the four lanes you are in, and everything after it is two commands that either work or name their own failure.
file myfile.bin
Run that first, and the question stops being how to open a .bin file and becomes which of the four things this one is.
Nothing in any of these lanes needs a package beyond the base system, so the same three commands and the same two-command lane work on every mainstream distribution.
That is the command I start with every time, and it has never sent me into a lane that was already wrong.
Frequently asked questions
What program opens a bin file in Linux?
The file command answers that first, and the program you need depends on what it reports. A shell script needs chmod +x and then the file itself, a disk image needs a loop mount, and raw data needs xxd or strings.
Can I open a bin file in a text editor?
You can, and it is worth doing for the first few lines. A self-extracting installer starts with a readable shell script, but everything after the header is compressed binary that a text editor cannot show you.
Does the method change on Kali Linux, Ubuntu, or Linux Mint?
No. The commands come from coreutils and util-linux, which every mainstream distribution ships, so the same three lines identify the file and the same lane opens it.
I ran chmod +x and the file still does nothing. Why?
Check what file reports about it. If the answer is data, a boot sector, or an ELF binary built for another architecture, the file was never a script, and the execute bit was never the missing piece.
