Check for file permission

Hi,

I have an array that has several directory paths and file paths.

I use a for loop to traverse through the array and check for files and not directories using the if condition.

I wish to display all files [not directories] that have permissions lesser than what the user has specified.

For example:

-rwxrwx---   2 user1      sie   8273920 Feb 24 15:13 /opt/app/hello.txt
-rwxr-x---   2 user1      sie   8273920 Feb 24 15:13 /opt/app/yellow.txt
-rwxrwxr-x   2 user1      sie   8273920 Feb 24 15:13 /opt/app/fellow.txt

So, if the user gives 770 which is read in a variable $1 then.

Expected result should be:

-rwxrwx---   2 user1      sie   8273920 Feb 24 15:13 /opt/app/hello.txt
-rwxrwxr-x   2 user1      sie   8273920 Feb 24 15:13 /opt/app/fellow.txt

Because the second entry is with permission 750 which is lesser permission the 770.

find with perm will do.
Below code will print all the files with permissions >= 750

find . -type f -perm -750

Below is the test case

-bash-4.1$ ls -lrt
total 12
-rwxr-x--- 1 username groupnm  55 Feb 25 05:43 table.dat
-rw-r--r-- 1 username groupnm 109 Feb 25 05:43 sample.dat
-rwxrwx--- 1 username groupnm 113 Feb 25 05:43 manipu.dat
-bash-4.1$ find . -type f -perm -750 | xargs ls -lrt
-rwxr-x--- 1 username groupnm  55 Feb 25 05:43 ./table.dat
-rwxrwx--- 1 username groupnm 113 Feb 25 05:43 ./manipu.dat
-bash-4.1$ find . -type f -perm -770 | xargs ls -lrt
-rwxrwx--- 1 username groupnm 113 Feb 25 05:43 ./manipu.dat
-bash-4.1$ find . -type f -perm -600 | xargs ls -lrt
-rwxr-x--- 1 username groupnm  55 Feb 25 05:43 ./table.dat
-rw-r--r-- 1 username groupnm 109 Feb 25 05:43 ./sample.dat
-rwxrwx--- 1 username groupnm 113 Feb 25 05:43 ./manipu.dat
-bash-4.1$

What have you tried so far?

I have the exact file name in an Array, so how could i use find ?

echo $arr[3]

-rwxrwx--- 2 user1 sie 8273920 Feb 24 15:13 /opt/app/hello.txt
Please let me know how can i use find with the array, if i can't, then what is the alternative ?

If the array has 10 elements, i.e., $arr[0] to $arr[9], below is the code

for i in $(seq 0 9);
do
find $(dirname $(echo ${arr[${i}]} | awk '{print $9}')) -type f -name $(basename $(echo ${arr[${i}]} | awk '{print $9}')) -perm -750
done
1 Like

As per the requirement that you specified in your first post you can try this:

find /path/to/your/directory -type f -perm -$yourPerm -exec ls -l {} \;

You shouldn't do that. for-loops can break if you have too many elements. Use a while-loop instead:

(( counter = 0 ))
while [ $counter -lt ${#array[*]} ] ; do
     command "${array[$counter]}"
     (( counter += 1 ))
done

What do you mean by "lesser"? If i specify "660" and the file turns out to be "750", is that lesser, more or something entirely different? How about "755" or "555"?

Please clarify.

bakunin

1 Like

SriniShoo's code helped !!

However, I need to know how would the same command work if the array contains both files and directories and I wish to check permissions for both.

I tried removing the type -f but that did not help.

Kindly suggest the changes.

---------- Post updated at 11:30 AM ---------- Previous update was at 10:43 AM ----------

660 is lesser than 750 becoz the [6]60 is less than [7]50.
755 is greater than 750 as all the permission are over met.
555 is lesser than 750 becoz [5]55 is less than [7]50.

Please let me know how can i tweak Srini's code to include directories along with files.

Just use "${arr[@]}" . You don't need to know how many elements exist nor do you need an external command like seq .

I disagree. Any runtime that can't iterate over its own arrays is badly broken.

Regards,
Alister

Thanks alister for the suggestion! you are correct about using

${arr[@]}

Below code will search for files / directories with permissions greater than or equal to given

PERM=750
for i in ${arr[@]}
do
ABS_FILE=$(echo ${i} | awk '{print $9}')
PATH=$(dirname ${ABS_FILE})
FILE=$(basename ${ABS_FILE})
find ${PATH} -name ${FILE} -perm -${PERM}
done

If you give that as the path variable, it will overwrite the default path variable used by the system.

My bad

The problem is not the iteration in itself. The problem is that expanding an array like "${array[*]}" might lead to a line that is longer than "MAXLINE" and/or consisting of more elements than "MAXARGS" allows for. You can experience the same phenomenon when using

for file in * ; do ...

Thi swill work well for any "normal" directory, but might break with a "line too long" if there are awful lots of entries in there. Instead of the for-loop the while-loop will not break:

ls | while read file ; do ...

I hope this helps.

bakunin

I'm assuming that by MAXLINE you mean LINE_MAX and that MAXARGS refers to ARG_MAX. In the case of expanding a for-loop's list, neither is relevant.

ARG_MAX limits the size of the command line and environment accepted by the execve system call. The for-loop does not execve the contents of the array; instead, it creates a list and consecutively binds each member to the same identifier.

LINE_MAX is the longest allowable line length (including the terminating newline character) in a text file. Expanding an array into a for-list using "${arr[@]}" does not generate a line or string. That double-quoted parameter expansion, like its positional parameter counterpart, "$@" , directly generates a list.

I don't think it's germane, but while we're on the subject of LINE_MAX and sh, POSIX sh exempts shell scripts from this limit:

Historical shells may indeed have hardcoded limits, but I suspect that any shell that supports arrays is sufficiently modern to utilize dynamic memory allocation. Virtual memory is almost certainly the actual limit.

I am not advocating against a while-loop. I have nothing against them. Some of my closest friends are while-loops. My point is simply that categorically advising against a for-loop is a bit much; given a modern shell and sufficient memory, the likelihood of a for-loop meltdown is nil.

There also exists the (remote) possiblity that the for-loop mentioned in the OP is the C-like variant supported by ksh93 and bash, which would allow array traversal using a simple index.

Regards,
Alister

1 Like

Some of your explanations (especially the part about POSIX exempting shell lines) were new to me. In fact what i said was because of personal experience - the ksh (ksh88) in AIX, definitely in version 4-something (i can't exactly remember which, maybe 4.1.4 or 4.2.1) exhibited exactly this problem. I remember researching the problem back then and i developed the habit of using for-loops very cautiously, because i *saw* them breaking under certain circumstances while while-loops always worked. (Basically i use for-loops only to cycle through a fixed number of elements - a number i know at programming time. For everything else i use while-loops.)

I have to admit, though, that i didn't bother to find out if this is still relevant knowledge for the last 15-20 years, so perhaps you are right and my advice is not relevant any more.

I stand corrected, thanks for the information.

bakunin