131

I know that certain processors are Big Endian and others are Little Endian. But is there a command, bash script, python script or series of commands that can be used at the command line to determine if a system is Big Endian or Little Endian? Something like:

if <some code> then
    echo Big Endian
else
    echo Little Endian
fi

Or is it more simple to just determine what processor the system is using and go with that to determine its Endianess?

3

13 Answers 13

151

On a Big Endian-System (Solaris on SPARC)

$ echo -n I | od -to2 | head -n1 | cut -f2 -d" " | cut -c6 

0

On a little endian system (Linux on x86)

$ echo -n I | od -to2 | head -n1 | cut -f2 -d" " | cut -c6 

1


The solution above is clever and works great for Linux *86 and Solaris Sparc.

I needed a shell-only (no Perl) solution that also worked on AIX/Power and HPUX/Itanium. Unfortunately the last two don't play nice: AIX reports "6" and HPUX gives an empty line.

Using your solution, I was able to craft something that worked on all these Unix systems:

$ echo I | tr -d [:space:] | od -to2 | head -n1 | awk '{print $2}' | cut -c6

Regarding the Python solution someone posted, it does not work in Jython because the JVM treats everything as Big. If anyone can get it to work in Jython, please post!

Also, I found this, which explains the endianness of various platforms. Some hardware can operate in either mode depending on what the O/S selects: http://labs.hoffmanlabs.com/node/544


If you're going to use awk this line can be simplified to:

echo -n I | od -to2 | awk '{ print substr($2,6,1); exit}'

For small Linux boxes that don't have 'od' (say OpenWrt) then try 'hexdump':

echo -n I | hexdump -o | awk '{ print substr($2,6,1); exit}'
5
  • 2
    That's an upper-case I (eye) rather than a lower-case l (ell) by the way. Jul 23, 2010 at 17:13
  • 1
    (Solaris) -> (Solaris, Sparc), although Sparc >= V9 is bi endian. Sep 17, 2010 at 22:13
  • 3
    Care to explain how it works?
    – Massimo
    Apr 1, 2016 at 11:40
  • This doesn't seem to work on Android (Nexus 5). Not sure why...
    – wjandrea
    Apr 9, 2017 at 17:20
  • printf "\x1" | od -to2 | awk 'NR==1{print$2==1}'
    – Kaz
    May 25, 2017 at 23:24
71

If you are on a fairly recent Linux machine (most anything after 2012) then lscpu now contains this information:

$ lscpu | grep Endian
Byte Order:            Little Endian

This was added to lscpu in version 2.19, which is found in Fedora >= 17, CentOS >= 6.0, Ubuntu >= 12.04.

Note that I found this answer from this terrific answer on Unix.SE. That answer has a lot of relevant information, this post is just a summary of it.

35

Here is a more elegant python one-line script

python -c "import sys;sys.exit(0 if sys.byteorder=='big' else 1)"

exit code 0 means big endian and 1 means little endian

or just change sys.exit to print for a printable output

1
  • 4
    This won't work on RHEL 5.x/CentOS 5.x systems which are running Python 2.4.x. Here's a fix: python -c "import sys;sys.exit(int(sys.byteorder!='big'))"
    – JPaget
    Jun 14, 2014 at 23:55
16

You can take advantage of ELF file format to determine the endianness of your system. For example, print the first six bytes of an arbitrary ELF file in hex:

xxd -c 1 -l 6 /bin/ls

0000000: 7f  .
0000001: 45  E
0000002: 4c  L
0000003: 46  F
0000004: 02  .
0000005: 01  .

If the last line (the sixth byte) is 01, according to ELF format, 01 is little endian and 02 is big endian.

If you haven't got an xxd on your box (and do have busybox), try this:

hexdump -s 5 -n 1 -C /bin/busybox
6
  • I think you mean of an arbitrary ELF ... Since there are other executable types including shell scripts, perl, python, etc. Not saying you're wrong otherwise though - just saying that it's worth remembering that there are other executable types (and for interest the code is in the text segment hence the old text file busy error).
    – Pryftan
    Feb 11, 2018 at 0:30
  • 1
    @Pryftan Thanks for pointing that out. Corrected it!
    – Tong Zhou
    Feb 11, 2018 at 20:36
  • @TongZhou Welcome; glad to be of help!
    – Pryftan
    Feb 12, 2018 at 14:39
  • Awesome! First method to work for busybox-based embedded OSes.
    – ogurets
    Nov 10, 2018 at 12:37
  • The hexdump version is awesome. It works well on busybox systems.
    – domenukk
    Feb 7, 2020 at 22:09
10

The main answer can be simplified slightly using awk:

On a Big Endian system (Solaris, SPARC)

$ echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}'
0

On a Little Endian system (Linux, Intel)

$ echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}'
1

Newer Linux Kernels

As of version 2.19 of the util-linux package the command lscpu started including a field related to Endianness. So now you can simply use this command to find this out:

$ lscpu | grep -i byte
Byte Order:            Little Endian

This has been confirmed on Ubuntu 12.10 and CentOS 6. So I would be willing to assume that most 3.0+ Linux Kernels are now offering this.

On Debian/Ubuntu systems you can also use this command, not sure of when it became available:

$ dpkg-architecture | grep -i end
DEB_BUILD_ARCH_ENDIAN=little
DEB_HOST_ARCH_ENDIAN=little

References

9

This Python script should work for you:

#!/usr/bin/env python
from struct import pack
if pack('@h', 1) == pack('<h', 1):
    print "Little Endian"
else:
    print "Big Endian"
1
  • 4
    One liner: python -c "from struct import pack;import sys;sys.exit(int(pack('@h',1)==pack('<h',1)))". The exit code is 0 for big endian and 1 for little endian. Sep 17, 2010 at 20:51
9
python -c "import sys; print(sys.byteorder)"

It would print the endianess of the system.

3

I found a way to do it in Jython. Since Jython (Python on the JVM) runs on a VM, it always reports big endian, regardless of the hardware.

This solution works for Linux, Solaris, AIX, and HPUX. Have not tested on Windows:

    from java.lang import System
    for property, value in dict(System.getProperties()).items():
        if property.endswith('cpu.endian'):
            return value
2

A single-line command based on ELF format:
hexdump -s 5 -n 1 /bin/sh

2
  • 1
    Edit: -n 1, sorry ;)
    – fae
    Apr 1, 2016 at 11:44
  • 3
    This is the exact same method as a previous answer, which also provided more details than yours.
    – kasperd
    Apr 1, 2016 at 12:31
2

I dislike a bit the answer that relies on the ELF format, as it is not used everywhere (it could be scripts, or another binfmt, or even a cygwin system). Here is a relatively portable which relies only on POSIX and hexdump (so busybox-compatible, if aiming for POSIX compatibility, awk should be used instead):

if test `printf '\0\1' | hexdump -e '/2 "%04x"'` -eq 0100
then
    echo little
else
    echo big
fi

Also test for middle-endian:

case `printf '\0\1\2\3' | hexdump -e '/4 "%08x"'` in
03020100) echo little;;
00010203) echo big;;
01000302) echo mid-big;;
02030001) echo mid-little;; # these two might be swapped, adjust accordingly
*) echo unknown endianness
esac

How is this working?

  1. Printf prints byte-by-byte, in order, 4 bytes (chars) whose hexadecimal values are: 00 01 02 03.
  2. That output buffer is piped to hexdump
  3. -e specifies a format string for hexdump to display data:
    • The /4 instructs it to apply formatting to groups of 4 bytes at once (from the man: The byte count is an optional positive integer. If specified it defines the number of bytes to be interpreted by each iteration of the format). That group will be read in hexdump's native endianess.
    • The "%08x" is the output format (8 hexadecimal chars with a leading 0).

The idea here is that hexdump is compiled for the platform it's running on, and will read the number in its native endianess, then display it in a "human-readable" big-endian format. X -> Y endian is the same swap as Y -> X (so swapping twice returns the input data).

Hexdump does the native -> big conversion for us, which we exploit here to perform a big -> native swap by specifying the word size. The use of hexdump was inspired by this answer.

0

Slightly different requirement: I need a test like this in a program build configure script to determine whether the compile target machine is bit or little endian, without executing code. The script must deposit #define HAVE_LITTLE_ENDIAN 1 into a config.h header, or else #define HAVE_LITTLE_ENDIAN 0.

The compile target machine may be different from the build machine, since we may be cross-compiling, which also explains why the test mustn't try to run any compiled code. It is out of the question to have a little C program with a printf statement that spits out the answer.

A possible solution is this. We generate a file called conftest.c which contains this:

#define USPELL(C0, C1, C2, C3) \                                             
  ((unsigned) C0 << 24 | \                                              
   (unsigned) C1 << 16 | \                                              
   (unsigned) C2 << 8 | (unsigned) C3)                                       

unsigned x[6] = {                                                       
  0,                                                                         
  USPELL('L', 'I', 'S', 'P'),                                                
  USPELL('U', 'N', 'I', 'X'),                                                
  USPELL('C', 'O', 'R', 'E'),                                                
  USPELL('D', 'W', 'I', 'M'),                                                
  0                                                                          
};

Now, we compile this to conftest.o using:

$ /path/to/cross-compiling/cc conftest.c -c

Then we run:

$ strings conftest.o
PSILXINUEROCMIWD

If the string PSILXINUEROCMIWD occurs, the target is little-endian. If the string LISPUNIXCOREDWIM occurs, it is big-endian. If neither string occurs or, even more astonishingly, both do, then the test has failed.

This approach works because the "fourcc" constants calculated in the program have machine-independent values, denoting the same integers regardless of endianness. Their storage representation in the object file follows the endianness of the target system, and that is visible via the character-based view under strings.

The two zero guard words ensure that the string is isolated. That isn't strictly necessary, but it ensures that the string we are looking for is not embedded in some other string, meaning that strings will output it on a line by itself.

P.S. the USPELL macro doesn't parenthesize the argument insertions because it's crafted for this specific purpose, not for re-use.

1
  • Not that it is necessary for all projects but does autoconf/automake not have this check? My projects are always small enough where I can make my own Makefiles (though not always basic) so I don't really know those tools other than making some modifications when necessary and the general interface..but I do wonder if they have detection. Perhaps you didn't need it even if it does, just thought I'd throw the possibility out.
    – Pryftan
    Feb 11, 2018 at 0:34
0

here's a solution that involves thoroughly mis-using posix shell exit codes :

gawk/mawk/mawk2/nawk 'BEGIN { # system() returns 1 
                              # if little-endian.
                              # to check BE, change that -c 2 to -c 5
     print system("
          exit \140<<<\47\47 gnu-od | grep -c 2\140") }'

\47 = ascii single quote, and \140 is ascii grave accent

  • except gnu-gawk -S sandbox mode, which disables system( )

what that does is execute this —>

exit ` <<<'' god | grep -c 2 `

inside a posix sh shell, basically asking gnu-od to show you a default 2-byte octals of a single \n (d=10) character.

on little-endian systems, it shows as 000012. But on big-endian systems, the extra padding byte causes gnu-od to upshift the octals. decimal of 10*256=2560=5x8x8x8, so the resulting 2-byte octal is 005000. Then use grep counter feature to locate either the 2 or the 5.

exit codes are supposed to be that 0 means success and every number larger means some sort of error. but since grep counter already helped us inverted that, the returned "exit code" of the system command is already in the awk boolean sense of true(1) and false(0).

0

On fairly modern Linux (6.2.16) x86_64:

$ time lscpu | grep 'Byte Order'
Byte Order:                      Little Endian

real    0m0.012s
user    0m0.000s
sys     0m0.007s


$ time echo '#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#warning LE
#else
#warning BE
#endif'| gcc -march=native -E - 2>&1 | sed -nr '/^.*[[:space:]]((B|L)E)[[:space:]].*$/{s/^.*[[:space:]]((B|L)E)[[:space:]].*$/\1/g;p;}'

LE

real    0m0.013s
user    0m0.006s
sys     0m0.013s

Since on some machines, endianness can depend on compiler options, and on setarch(1) / personality(2) settings, and the execution times are very similar, between above commands, I'd use gcc >= v12 with above options to get native bit order for current personality(2) , if you have a C compiler installed -- this also permits use of different -march=/-mtune/-mcpu settings to "lookup" Endianness of other CPU variants / architectures.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .