Can the Unix list command 'ls' output numerical chmod permissions?
Is it possible when listing 开发者_StackOverflow中文版a directory to view numerical unix permissions such as 644 rather than the symbolic output -rw-rw-r--
Thanks.
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}'
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
you can just use GNU find.
find . -printf "%m:%f\n"
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' *
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' *
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;}'"
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
@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
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.
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}"
}
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
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
>>l [SOME DIRECTORY]
P.S. Please excuse my very long (3 line) prompt (PS1)
精彩评论