253

Is it possible when listing a directory to view numerical Unix permissions such as 644, rather than the symbolic output -rw-rw-r-- ?

Thanks.

informatik01
  • 16,038
  • 10
  • 74
  • 104
Jon Winstanley
  • 23,010
  • 22
  • 73
  • 116

13 Answers13

415

it almost can ..

 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}'
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
miku
  • 181,842
  • 47
  • 306
  • 310
  • 40
    For creating it as an alias (example below: 'cls' command), use: ```alias cls="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}'"``` – Melroy van den Berg Mar 06 '14 at 16:15
  • 6
    I copy and pasted the line from danger89 and found that strangely the output began with %0..o per line, instead of say 755. If anyone else comes across this, the cause appears to be a hidden character between the 0 and o. Once deleted the command is set up nicely. Cheers! – Donna Mar 09 '14 at 17:31
  • I think there is an calculation issue. After `chmod 777 dir` your command prints permissions as `767` – Julian F. Weinert Apr 24 '14 at 10:55
  • As Donna mentions, there is a funny character (or 2) between the 0 and o, also, weirdly it looks like SO is adding it... – nbsp Nov 17 '14 at 19:49
  • Does anyone have a working alias for this command? awk runtime error involving "%0o " on a debian derivative – cremefraiche Oct 18 '15 at 00:01
  • 5
    This fails to recognize bits t and s. You should use the 'stat' command to get the file permission information. Calculating it by hand will lead to errors! – Evan Langlois Nov 09 '15 at 06:28
  • @danger89 `awk` actually preserves the color if you use the `ls` option `--color`, too. – Geremia Feb 28 '16 at 03:21
  • Nice but doesnt work in www.codeanywhere.com virtual machine terminal. awk: cmd. line:3: awk: cmd. line:3: ^ unexpected newline or end of string awk: cmd. line:3: *2^(8-i));if(k)printf("%0o ",k);print} awk: cmd. line:3: ^ syntax error awk: cmd. line:3: *2^(8-i));if(k)printf("%0o ",k);print} awk: cmd. line:3: ^ syntax error awk: cmd. line:3: *2^(8-i));if(k)printf("%0o ",k);print} awk: cmd. line:3: ^ syntax error – Kangarooo Mar 24 '16 at 23:15
193

Closest I can think of (keeping it simple enough) is stat, assuming you know which files you're looking for. If you don't, * can find most of them:

/usr/bin$ stat -c '%a %n' *
755 [
755 a2p
755 a2ps
755 aclocal
...

It handles sticky, suid and company out of the box:

$ stat -c '%a %n' /tmp /usr/bin/sudo
1777 /tmp
4755 /usr/bin/sudo
JB.
  • 40,344
  • 12
  • 79
  • 106
  • 32
    This works great under Linux, I found `stat -f '%A %N' *` does the same thing on a mac (FreeBSD) – reevesy May 29 '14 at 12:07
  • 2
    I guess the argument is that `stat` is not `ls` therefore this is not the correct answer. However, I believe this is the correct answer in context of the desired output. If `awk` is permitted in a pipe, then `find` should be permitted where `stat` is called in `-exec`; then you can use `stat` directly without `*` – javafueled Mar 04 '15 at 14:29
  • 3
    This is much better shorter and 100% working on any system – Kangarooo Mar 24 '16 at 23:15
  • If you want to use stat to see the rights recursively, under bash, use `stat -c '%a %n' * **/*`. – Denis Chevalier Aug 11 '17 at 13:37
  • according to `man stat -c or --format`: `%a access rights in octal (note '#' and '0' printf flags), %n file` – Timo Jul 12 '21 at 13:28
77

you can just use GNU find.

find . -printf "%m:%f\n"
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
52

You can use the following command

stat -c "%a %n" *

Also you can use any filename or directoryname instead of * to get a specific result.

On Mac, you can use

stat -f '%A %N' *
Mohd Abdul Mujib
  • 13,071
  • 8
  • 64
  • 88
  • 1
    Didn't work for me. `stat: illegal option -- c` `usage: stat [-FlLnqrsx] [-f format] [-t timefmt] [file ...]` – rschwieb Mar 14 '16 at 19:25
  • 1
    works on ubuntu 14.04.. to never have to remember this I've added an alias in my .bashrc: alias xxx="stat -c '%a %n' *" – faebster Apr 29 '16 at 01:52
  • 3
    Helpful! How you dig it out the %A which not even shows up in man of stat on Mac? – igonejack Jan 17 '18 at 03:43
  • 1
    It actually is a FreeBSD command, and Mac just happens to be built upon that using it as upper kernel. – Mohd Abdul Mujib Jan 17 '18 at 04:44
  • If we only use the information presented in `man stat` on macOS 10.14.4, then the command should be `stat -f "%Lp %N" *`. `%Lp` appears to print the same thing as `%A`. – Cesar Andreu Apr 03 '19 at 07:03
23

Use this to display the Unix numerical permission values (octal values) and file name.

stat -c '%a %n' *

Use this to display the Unix numerical permission values (octal values) and the folder's sgid and sticky bit, user name of the owner, group name, total size in bytes and file name.

stat -c '%a %A %U %G %s %n' *

enter image description here

Add %y if you need time of last modification in human-readable format. For more options see stat.

Better version using an Alias

Using an alias is a more efficient way to accomplish what you need and it also includes color. The following displays your results organized by group directories first, display in color, print sizes in human readable format (e.g., 1K 234M 2G) edit your ~/.bashrc and add an alias for your account or globally by editing /etc/profile.d/custom.sh

Typing cls displays your new LS command results.

alias cls="ls -lha --color=always -F --group-directories-first |awk '{k=0;s=0;for(i=0;i<=8;i++){;k+=((substr(\$1,i+2,1)~/[rwxst]/)*2^(8-i));};j=4;for(i=4;i<=10;i+=3){;s+=((substr(\$1,i,1)~/[stST]/)*j);j/=2;};if(k){;printf(\"%0o%0o \",s,k);};print;}'"

Alias is the most efficient solution

Folder Tree

While you are editing your bashrc or custom.sh include the following alias to see a graphical representation where typing lstree will display your current folder tree structure

alias lstree="ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/   /' -e 's/-/|/'"

It would display:

   |-scripts
   |--mod_cache_disk
   |--mod_cache_d
   |---logs
   |-run_win
   |-scripts.tar.gz
Erick Gonzalez
  • 343
  • 3
  • 6
19

@The MYYN

wow, nice awk! But what about suid, sgid and sticky bit?

You have to extend your filter with s and t, otherwise they will not count and you get the wrong result. To calculate the octal number for this special flags, the procedure is the same but the index is at 4 7 and 10. the possible flags for files with execute bit set are ---s--s--t amd for files with no execute bit set are ---S--S--T

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

For test:

touch blah
chmod 7444 blah

will result in:

7444 -r-Sr-Sr-T 1 cheko cheko   0 2009-12-05 01:03 blah

and

touch blah
chmod 7555 blah

will give:

7555 -r-sr-sr-t 1 cheko cheko   0 2009-12-05 01:03 blah
user224243
  • 399
  • 1
  • 5
5

You don't use ls to get a file's permission information. You use the stat command. It will give you the numerical values you want. The "Unix Way" says that you should invent your own script using ls (or 'echo *') and stat and whatever else you like to give the information in the format you desire.

Evan Langlois
  • 4,050
  • 2
  • 20
  • 18
3
ls -lvahF --color \
    | awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf("%0o\t",k);print $5,$6,$7,$8,$NF}' \
    | column -t

This does: sort by name, coloring, decimal numbers permissions, and aligns to columns.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
mdma
  • 31
  • 1
2

Building off of the chosen answer and the suggestion to use an alias, I converted it to a function so that passing a directory to list is possible.

# ls, with chmod-like permissions and more.
# @param $1 The directory to ls
function lls {
  LLS_PATH=$1

  ls -AHl $LLS_PATH | 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}"
}
Community
  • 1
  • 1
Curtis Blackwell
  • 3,130
  • 3
  • 27
  • 45
  • Doesn't work for some UNIX: `ls: ERROR: Illegal option -- H` then `usage: ls -1ACFLRTabcdfgilmnopqrstux -W[sv] [files]` and `awk: cmd. line:2: fatal: file '/usr/include' is a directory` – kbulgrien Oct 06 '20 at 18:04
2

Solution

It is strange that still nobody mentioned the (quote) "modern replacement for ls" - an alternative and quite powerful tool exa.

You can easily achieve the desired output by using exa command along with the -l (which is equivalent to ls's -l) and the --octal-permissions options.


Example

Here is a simple example of listing the contents of a user's root directory (/) on a macOS machine using exa command and the --octal-permissions option:

exa -lh --octal-permissions /

Result:

enter image description here

Notice how besides the nice colorful output exa can also show the headers for each column thanks to the -h option (long form is --header).

Read man exa or the official online documentation for more information about how to customize the desired output according to your specific needs.


The official project page on GitHub:

informatik01
  • 16,038
  • 10
  • 74
  • 104
0

Considering the question specifies UNIX, not Linux, use of a stat binary is not necessary. The solution below works on a very old UNIX, though a shell other than sh (i.e. bash) was necessary. It is a derivation of glenn jackman's perl stat solution. It seems like an alternative worth exploring for conciseness.

$ alias lls='llsfn () { while test $# -gt 0; do perl -s -e \
  '\''@fields = stat "$f"; printf "%04o\t", $fields[2] & 07777'\'' \
    -- -f=$1; ls -ld $1; shift; done; unset -f llsf; }; llsfn'
$ lls /tmp /etc/resolv.conf
1777    drwxrwxrwt   7 sys      sys       246272 Nov  5 15:10 /tmp
0644    -rw-r--r--   1 bin      bin           74 Sep 20 23:48 /etc/resolv.conf

The alias was developed using information in this answer

The whole answer is a modified version of a solution in this answer

kbulgrien
  • 4,384
  • 2
  • 26
  • 43
0

After reading MANY answers here, following links provided in comments back to the original UNIX way of doing this, and while wanting to combined what was offered here, as well as the tips and tricks I've already learned, I came up with a new solution.

First off, I used to use this alias, to give me column headers:

alias l='echo "Dir Size|Perms|Link Count|Owner|Group|Size|Mod. Time|Name"; ls -haFl --time-style=long-iso --color=always --group-directories-first --format=long'

After combining this, with AWK, I first learned I had to alter the awk command, when using the "-s" option for ls, as this shows size in the first column, and you need to then read and parse the second (no longer first) column of data.

The ISSUE I found, was when you then provide input to " l " i.e., you are at a path, and type: l, fine, but what if you type "l" then a directory name? what if you want to list out everything in a subdirectory? This wasn't able to happen, as the alias did not handle input. I was able to handle this with a function. Then AWk broke, which I was able to handle with a sub-alias.

Combining the two worked perfectly.

Added to my .bashrc file

function _bestLS() {
  echo 'MODE|Dir Size|Perms|Link Count|Owner|Group|Size|Mod. Time|Name';
  if [ "$*" == '' ]; then
     alias _awk4ls="awk '{k=0;s=0;for(i=0;i<=8;i++){;k+=((substr(\$2,i+2,1)~/[rwxst]/)*2^(8-i));};j=4;for(i=4;i<=10;i+=3){;s+=((substr(\$1,i,1)~/[stST]/)*j);j/=2;};if(k){;printf(\"%0o%0o \",s,k);};print;}'";
     output=`ls -shaFl --time-style=long-iso --color=always -F --group-directories-first --format=long | _awk4ls`;
  else
     output=`ls -shaFl --time-style=long-iso --color=always -F --group-directories-first --format=long $* | _awk4ls`;
  fi
  echo "$output"
}
alias l="_bestLS"

Observe (please note, it is a lower case letter L, not a numeric 1, which look the same in this site's font):

>>l

typing just l

>>l [SOME DIRECTORY]

typing l, then a folder name

P.S. Please excuse my very long (3 line) prompt (PS1)

PyTis
  • 1,054
  • 10
  • 13
0

Could be improved but thats how i roll for now

sudo echo "alias ll=\"ls -lha --color=always -F --group-directories-first |awk '{k=0;s=0;for(i=0;i<=8;i++){;k+=((substr(\\\$1,i+2,1)~/[rwxst]/)*2^(8-i));};j=4;for(i=4;i<=10;i+=3){;s+=((substr(\\\$1,i,1)~/[stST]/)*j);j/=2;};if(k){;printf(\\\"%0o%0o \\\",s,k);};print;}'\"" | sudo tee -a /etc/profile.d/00-aliases.sh

source /etc/profile.d/00-aliases.sh
Mystix
  • 1