510

There is a chmod command to set file permissions, but can I get file permissions in octal mode (such as 755) from the command line?

2
  • 4
    For people like me who accidentally landed on this page but actually were searching for how to do this on Mac: stackoverflow.com/a/14855227/470749
    – Ryan
    Jan 8, 2019 at 0:20
  • 2
    stat --format "%A" $FILE gives you the human readable drwxr-x--- format. which may or may not be useful. May 27, 2019 at 15:10

7 Answers 7

715

You can try

stat -c "%a %n" *

Replace * with the relevant directory or the exact filename that you want to examine.

From the man page of stat,

-c  --format=FORMAT
          use  the  specified  FORMAT instead of the default; output a newline after
          each use of FORMAT
%a     Access rights in octal
%n     File name

Usage:

  • With files:

    $ stat -c "%a %n" ./Documents/Udev.html 
    664 ./Documents/Udev.html
    
  • With folders:

    $ stat -c "%a %n" ./Documents/
    755 ./Documents/
    

(Reference)

11
  • 75
    on mac os, use stat -f '%A %a %N' * (credit: geeklog.adamwilson.info/article/58/…)
    – s2t2
    Apr 15, 2015 at 22:07
  • 7
    @usandfriends looping on the output of ls is a bad idea. If you really want to use a loop you can do for f in *; do stat "%a %n" "$f"; done
    – Tom Fenech
    Feb 18, 2016 at 10:12
  • 2
    Why on mac os everything is slightly changed (even in unix iso utils)? Is there an actual reason of this?
    – Vassilis
    Aug 21, 2016 at 2:32
  • 2
    Please @hackel, tell us how you really feel. lol! May 30, 2017 at 7:31
  • 2
    @Vassilis Answer: Know. The question you're really asking is: "if BSD came out before Linux, why did Linux change the standards instead of following the pattern set by older UNIX systems?". Nov 15, 2018 at 19:01
68

File permissions in Linux can be displayed in octal format using Linux stat command.

Just press Ctrl+Alt+T on your keyboard to open Terminal. When it opens, Navigate to the directory where you want to find the file permissions in octal mode.

stat -c '%A %a %n' *

%A Access rights in human readable form

%a Access rights in octal

%n File name

Octal numbers and permissions

You can use octal number to represent mode/permission:

r: 4
w: 2
x: 1

For example, for file owner you can use octal mode as follows. Read, write and execute (full) permission on a file in octal is 0+r+w+x = 0+4+2+1 = 7

Only Read and write permission on a file in octal is 0+r+w+x = 0+4+2+0 = 6

Only read and execute permission on a file in octal is 0+r+w+x = 0+4+0+1 = 5

Use above method to calculate permission for group and others. Let us say you wish to give full permission to owner, read & execute permission to group, and read only permission to others, then you need to calculate permission as follows: User = r+w+x = 0+4+2+1 = 7 Group= r+w+x = 0+4+2+0 = 6 Others = r+w+x = 0+0+0+1 = 1

Effective permission is 761.

Source: http://kmaiti.blogspot.com/2011/09/umask-concept.html

3
  • 2
    The initial 0 represent special bit too: pastebin.com/6ymkFt71
    – Braiam
    Jul 28, 2013 at 1:45
  • is it possible to force 4 digit output? Jan 3, 2021 at 1:50
  • 1
    To include hidden files/folders starting with dot (eg. .git) you can use stat -c '%A %a %n' .* *
    – Sharak
    May 12, 2021 at 8:11
44

As detailed in “755”-style permissions with ‘ls’ by Adam Courtemanche on AgileAdam.com, you can create an alias lso that acts like ls -l but slightly processes the output1 to display permissions also in octal. This adds a leading column showing three-digit2 octal permissions. As written, this works for most files and directories, but it does not work properly if the sticky or setuid/setgid bits are set.3

alias lso="ls -alG | awk '{k=0;for(i=0;i<=8;i++)k+=((substr(\$1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf(\" %0o \",k);print}'"

This has a serious shortcoming, though, as techtonik points out. You cannot pass arguments to this lso alias as you would to the ls command, because they are taken as additional arguments to awk instead. Thus you cannot run lso on a specific file or directory, nor can you pass any options (like -F, or --color) to lso.


The fix is to define lso as a function rather than an alias.

lso() { ls -alG "$@" | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf(" %0o ",k);print}'; }

If you're trying this out interactively in your shell, run unalias lso to remove the alias--you can do that either before or after you define the function. If you're putting it into a file that is sourced, such as ~/.bashrc, just take out the alias line and add the function definition.

Why does this work? Unlike aliases, bash shell functions can take positional parameters, i.e., command-line arguments. "$@" expands to the full argument list, causing arguments to the lso function to be passed to ls. (Unlike an alias definition, a function body is not quoted; hence it was necessary to remove the \characters before $ and ".)

Since you can pass options to lso when defined this way as a function, you may wish to remove the -a and -G options from the definition--you can pass them manually in cases where you want them. (The -l option is required for details like file permissions to be shown at all, so there is no benefit to removing it.)

lso() { ls -l "$@" | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf(" %0o ",k);print}'; }

Thanks to techtonik for pointing out the limitation in defining lso as an alias, thus motivating me to expand this post with material about making it a function instead.


1One may note this seems to flout the general rule about not parsing output from ls. ls produces very human-readable output; this introduces idiosyncrasies and limitations making it generally unsuitable as input for other commands. In this case we parse ls since we wish to preserve the exact behavior of ls except our one added change.

2One limitation of this alias, which also applies to the function version shown below it, and which may be considered a bug, is that it only displays three octal digits even when the fourth octal digit is zero. As jfmercer has rightly pointed out, the octal digits displayed here don't reflect the sticky bit if present, nor setuid or setgid bits.

3More seriously than merely not showing the fourth octal digit is that this method assumes they are not set, and if they are--if you see t, s, or S in the permission string--then you should disregard the octal digits. This because the bits are inferred from the permissions string in a way that does not account for sticky setuid/setgid bits.

4
  • doesn't work with directories - awk: read error (Is a directory) Jul 25, 2014 at 7:25
  • @techtonik Thanks for pointing this out! I've (finally) updated this answer to include a fix for that. Apr 10, 2015 at 20:37
  • 2
    You can add --color parameter for show colors lso() { ls -alG "$@" --color | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf(" %0o ",k);print}'; }
    – tagplus5
    Mar 13, 2017 at 0:03
  • 1
    have you discovered a solution to the sticky setuid/setgid issue since posting this?
    – user428026
    Mar 3, 2019 at 4:00
29

Just extending\simplifying previous 'stat' related answers:

You can simply run:

stat <path_to_file>

The output will contain octal permission along with other info.



Details(stat version and example):

# stat --version
stat (GNU coreutils) 8.4


[user@localhost ~]# touch /tmp/TEST_PERMISSONS

[user@localhost ~]# chmod 644 /tmp/TEST_PERMISSONS

[user@localhost ~]# stat /tmp/TEST_PERMISSONS
  File: `/tmp/TEST_PERMISSONS'
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 1010058     Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2015-08-26 18:58:59.000000000 +0300
Modify: 2015-08-26 18:58:59.000000000 +0300
Change: 2015-08-26 18:59:16.000000000 +0300

Note the: (0644/-rw-r--r--)

0
11

For portability, you can use perl:

$ perl -e 'printf "%04o %s\n", (stat)[2] & 07777, $_ for @ARGV' *.txt
0644 1.txt
0644 2.txt
0644 3.txt
0644 4.txt
0600 PerlOneLiner.txt
0664 perl.txt

If you want to notice when an error occurs, try:

perl -e '
for (@ARGV) {
    print "$!: $_\n" and next unless -e;
    printf "%03o %s\n", (stat)[2] & 07777, $_;
}
' *.txt
3
  • 2
    In addition to being portable, @cuonglm's solution shows four octal characters rather than three, thus showing the state of the "sticky bit" that is often forgotten about.
    – jfmercer
    Jul 22, 2015 at 14:28
  • how about show hidden files ?
    – MaXi32
    May 14, 2020 at 21:28
  • @MaXi32 use .*
    – cuonglm
    May 15, 2020 at 2:45
4

You can use find with the -printf action.

ls doesn't show octal permissions, but you can use this find-based workaround:

find path -printf "%m:%f\n"

For example, to check my Videos directory:

$ find Videos -printf "%m:%f\n"
755:Videos

The %m format specifier tells the -printf action to print octal permissions, while the %f format specifier causes it to print the filename.

You can pass multiple filenames to find. You can even use globs (e.g., find * -printf "%m:%f\n").

You don't have to use a test like -name or -iname; it is sufficient to pass the names of the files or directories you are interested in as starting points to find. That is, supply their names as arguments immediately after the word find, as shown above.

find gives you great control over how it shows output. There are two modifications in particular that you might find useful:

  • By default, find recurses subdirectories, similar to ls -R. If you don't want find to visit the subdirectories of the starting points you pass to it, you can add -maxdepth 0 (or use -maxdepth with other values to indicate how deep you want it to go).

    $ find Documents -maxdepth 0 -printf "%m:%f\n"
    755:Documents
    
  • %f only shows a filename, so if find has to recurse to get to a file, you might not know where it is located. To show a path, beginning with whichever starting point the file was found under, use %p instead.

    $ find /boot -printf "%m:%p\n"
    755:/boot
    644:/boot/initrd.img-4.4.0-92-generic
    600:/boot/System.map-4.4.0-93-generic
    600:/boot/vmlinuz-4.4.0-92-generic
    600:/boot/vmlinuz-4.4.0-93-generic
    ....

See man find for more information about using the find command.

Another Method (ls and awk)

This can be used to list all directory files with their permissions:

ls -l | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/) \
             *2^(8-i));if(k)printf("%0o ",k);print}'

This is essentially the same command as in Adam Courtemanche's lso alias, which that answer cited, just run as a single command. If you're only using this once, or on rare occasion, then you might not want to bother writing it as an alias or shell function.

0

You can use an alias that will show listing somewhat similar to "ls":

alias lm='stat -c "%-05a %-12A %-5U %5G %s   %-015F %n" * | numfmt --to=iec --field=5 --padding=6'

You must log in to answer this question.

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