Skip to content

Instantly share code, notes, and snippets.

@beugley
Created February 6, 2017 21:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beugley/47b4812df0837fc90e783347faee2432 to your computer and use it in GitHub Desktop.
Save beugley/47b4812df0837fc90e783347faee2432 to your computer and use it in GitHub Desktop.
Python script to convert a Linux octal permission number to a text string
def perm_to_text(perm):
perms = {
"0": "---",
"1": "--x",
"2": "-w-",
"3": "-wx",
"4": "r--",
"5": "r-x",
"6": "rw-",
"7": "rwx"
}
if len(perm) == 4:
first = perm[0]
perm = perm[1:]
else:
first = ""
try:
outperms = ""
for p in perm:
outperms += perms[p]
except KeyError as e:
outperms = perm
if first != "":
if first == '0':
pass
elif first == '1':
pass
elif first == '2':
if outperms[5] == 'x':
outperms = outperms[:5]+'s'+outperms[6:]
else:
outperms = outperms[:5]+'S'+outperms[6:]
elif first == '4':
if outperms[2] == 'x':
outperms = outperms[:2]+'s'+outperms[3:]
else:
outperms = outperms[:2]+'S'+outperms[3:]
else:
outperms = perm
return "-"+outperms
@mpdrsn
Copy link

mpdrsn commented Jan 22, 2020

How about something simpler (sorry for the formatting):
def perm_to_text(octal):
result = ""
value_letters = [(4, "r"), (2, "w"), (1, "x")]
# Iterate over each of the digits in octal
for permission in [int(n) for n in str(octal)]:
# Check for each of the permissions values
for value, letter in value_letters:
if permission >= value:
result += letter
permission -= value
else:
result += "-"
return result

@alaakh42
Copy link

alaakh42 commented Apr 3, 2020

Thanks! @mpdrsn

@upwkwd
Copy link

upwkwd commented Apr 23, 2020

Thanks @mpdrsn so much.

@shanhas
Copy link

shanhas commented May 12, 2020

Thank u

@hack-tramp
Copy link

hack-tramp commented Jul 6, 2020

Warning : the above functions do NOT deal with four digit chmod octals.

When the octal is 4 digits long, the first digit is a setuid, setguid or sticky flag. See here for more info: https://linuxize.com/post/chmod-command-in-linux/ and here: https://en.wikipedia.org/wiki/File_system_permissions#Notation_of_traditional_Unix_permissions

Below is a version of the above function which correctly deals with four digit octals - be warned, it is not elegant!

def perm_to_text(octal):
   result =  ''
   first = 0
   octal = str(octal)
   #if there are more than 4 digits, just take the last 4
   if len(octal)>4:
      #separate initial digit
      octal = octal [-4:]
   #if there are 4 digits, deal with first (setuid, setgid, and sticky flags) separately
   if len(octal)==4:
      if octal[0]!='0': 
         first = int(octal [:1])
      octal = octal [-3:]
   value_letters = [(4, 'r'), (2, 'w'), (1, 'x')]
   # Iterate over each of the digits in octal
   for permission in [int(n) for n in octal]:
      # Check for each of the permissions values
      for value, letter in value_letters:
         if permission >= value:
            result += letter
            permission -= value
         else:
            result += '-'
   if first!=0:
      for value in [4,2,1]:
         if first >= value:
            if value==4:
               if result[2] == 'x':
                  result = result[:2]+'s'+result[3:]
               elif result[2] == '-':
                  result = result[:2]+'S'+result[3:]
            if value==2:
               if result[5] == 'x':
                  result = result[:5]+'s'+result[6:]
               elif result[5] == '-':
                  result = result[:5]+'S'+result[6:]            
            if value==1:
               if result[8] == 'x':
                  result = result[:8]+'t'+result[9:]
               elif result[8] == '-':
                  result = result[:8]+'T'+result[9:]             
            first -= value   
   
   return result

print(perm_to_text('3777'))
#rwxrwsrwt
print(perm_to_text('2775'))
#rwxrwsr-x

@JustinTimperio
Copy link

JustinTimperio commented Aug 21, 2020

Thanks for writing and posting this! This was very helpful in writing my own parser. If you need to convert from symbolic to numeric you can use this function.

def perm_to_num(symbolic):
    '''
    Convert symbolic permission notation to numeric notation.
    '''
    perms = {
            '---': '0',
            '--x': '1',
            '-w-': '2',
            '-wx': '3',
            'r--': '4',
            'r-x': '5',
            'rw-': '6',
            'rwx': '7'
        }

    # Trim Lead If It Exists
    if len(symbolic) == 10:
        symbolic = symbolic[1:]

    # Parse Symbolic to Numeric
    x = (symbolic[:-6], symbolic[3:-3], symbolic[6:])
    numeric = perms[x[0]] + perms[x[1]] + perms[x[2]]
    return numeric

This will convert input like '-rw-r--r--' to '644'

@pxcluster
Copy link

pxcluster commented Oct 22, 2020

Sorry, my function does exactly the reverse of the initial question... It's like the post from Justin Timperio

I have a version which handles the additional permissions like Sticky bit, Set User/Group bits. For instance, it converts 'rwsr-Sr-T'. Note that my code is extracted from my tools and allows to pass an octal value (usually a mistake). Here is the code 👍

def set_fmode(value) :
    """
    Convert a 'rwsr-xr-T' format to a decimal value
    """

    lvalue = len(value)

    # Check if 'value' has the right format
    if (isinstance(value,
                   str)
        and not [x for x in value if x not in '-rwxXsStT']
        and lvalue == 9) :

        pos = lvalue - 1
        res = 0
        for c in value :
            if c in 'sStT' :
                # Special modes
                res += (1 << pos // 3) << 9

            res += 1 << pos if c in 'rwxst' else 0
            pos -= 1

    elif isinstance(value,
                    int) :
        res = value

    else :
        raise ValueError
    
    return res

@Roffild
Copy link

Roffild commented Mar 22, 2022

import stat
stat.filemode(0o107664) # '-rwSrwSr-T'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment