Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game. |
| Notices |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
07-23-2005, 08:59 PM
|
#1
|
|
Member
Registered: Oct 2003
Location: Canada
Distribution: Slackware
Posts: 340
Rep:
|
Help with a recursive chmod script in bash
I've wanted to write a script like this for a while, but I always get stuck. Lets say I have an insecured web directory or something, and all the files have way more permissions then they should have. And say the directories can run very deep on the webserver, like up to 9 subdirectories containing web files.
I want to write a script that starts at the current directory (in this case, /usr/local/apache/htdocs), then goes through and gives the proper chmod permissions based on what type of file something is. If its a directory, I want to execute `chmod 711 $file`, and recurse into the directory and test everything again. If its a file I want to execute a `chmod 644 $file` and leave it like so.
I think I need some sort of callback function. I can't use chmod -R by the way, because that will give the same permissions to EVERYTHING, and I want more control than that.
If I just needed to secure a top-level directory, I would do it like this:
Code:
#!/bin/bash
for file in *
do
if [ -f "$file" ];
then
chmod 644 $file
else
if [ -d "$file" ];
then
chmod 711 $file
fi
fi
done
That works (at least I'm pretty sure, I wrote a very similiar script before, my syntax could be off on the if/else stuff). Can anyone point me in the right direction?
Thanks.
|
|
|
|
07-24-2005, 01:14 AM
|
#2
|
|
Moderator
Registered: Apr 2002
Location: in a fallen world
Distribution: slackware by choice, others too :} ... android.
Posts: 22,903
|
Code:
#!/bin/bash
find -type d -exec chmod 711 {} \;
find -type f -exec chmod 664 {} \;
Cheers,
Tink
|
|
|
|
07-24-2005, 01:34 AM
|
#3
|
|
Moderator
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,505
Rep: 
|
Re: Help with a recursive chmod script in bash
Quote:
Originally posted by lowpro2k3
Code:
#!/bin/bash
for file in *
do
if [ -f "$file" ];
then
chmod 644 $file
else
if [ -d "$file" ];
then
chmod 711 $file
fi
fi
done
That works (at least I'm pretty sure, I wrote a very similiar script before, my syntax could be off on the if/else stuff). Can anyone point me in the right direction?
Thanks.
|
While Tink's suggestion above is good, if you still want more control, just change your script like so:
Code:
#!/bin/bash
MYDIR="."
if [ -n "$1" ]
then MYDIR=$1
fi
for file in *
do
if [ -f "$file" ];
then
chmod 644 $file
else
if [ -d "$file" ];
then
chmod 711 $file
$0 $MYDIR/$file
fi
fi
done
|
|
|
|
07-24-2005, 06:18 AM
|
#4
|
|
Senior Member
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
|
David,
I don't see the recursion in your solution, please enlighten me.
Tink,
Elegant code; however the following may be faster, albeit klugey:
Code:
#!/bin/bash
chmod -R 664 *
find -type d -exec chmod 711 {} \
I don't know if any speed difference is significant.
lowpro2k3,
Your double 'fi' bothers me, the following structure works just as well & is a bit cleaner:
Code:
#!/bin/bash
for file in *
do
if [ -f "$file" ];
then
echo "file: $file"
elif [ -d "$file" ];
then
echo " dir: $file"
fi
done
(I changed your chmod's to echo's for testing purposes.)
|
|
|
|
07-24-2005, 11:41 AM
|
#5
|
|
Moderator
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,505
Rep: 
|
The recursion in my solution comes from two parts...
1) The script now takes an argument that is the name of the directory to be processed. If no directory is specified, it makes it "." by default.
2) When encountering a directory, the script calls itself with that directory as an argument.
Admittedly, there was one small error in my script, which is corrected below.
Code:
#!/bin/bash
MYDIR="."
if [ -n "$1" ]
then MYDIR=$1
fi
for file in $MYDIR/*
do
if [ -f "$file" ]
then
chmod 644 $file
elif [ -d "$file" ]
then
chmod 711 $file
$0 $MYDIR/$file
fi
done
|
|
|
|
07-24-2005, 12:14 PM
|
#6
|
|
Member
Registered: Oct 2003
Location: Canada
Distribution: Slackware
Posts: 340
Original Poster
Rep:
|
Quote:
Originally posted by Tinkster
Code:
#!/bin/bash
find -type d -exec chmod 711 {} \;
find -type f -exec chmod 664 {} \;
Cheers,
Tink
|
Wow, very nice, I always seem to forget about find! Thanks, I'll be using that alot now.
Quote:
Originally posted by archtoad6
lowpro2k3,
Your double 'fi' bothers me, the following structure works just as well & is a bit cleaner:
Code:
#!/bin/bash
for file in *
do
if [ -f "$file" ];
then
echo "file: $file"
elif [ -d "$file" ];
then
echo " dir: $file"
fi
done
(I changed your chmod's to echo's for testing purposes.)
|
Thanks, I almost never program in bash and I did a _quick_ search through the bash programming guide and didn't see the 'elif' structure. Much cleaner.
Quote:
Originally posted by Matir
The recursion in my solution comes from two parts...
1) The script now takes an argument that is the name of the directory to be processed. If no directory is specified, it makes it "." by default.
2) When encountering a directory, the script calls itself with that directory as an argument.
Admittedly, there was one small error in my script, which is corrected below.
Code:
#!/bin/bash
MYDIR="."
if [ -n "$1" ]
then MYDIR=$1
fi
for file in $MYDIR/*
do
if [ -f "$file" ]
then
chmod 644 $file
elif [ -d "$file" ]
then
chmod 711 $file
$0 $MYDIR/$file
fi
done
|
I haven't had a chance to run the script yet, but I think thats exactly what I'm looking for. I forgot the '$0' was the name of the script in bash, very nice.
Quick question, if a top level directory (say /usr/local/apache/htdocs) had multiple directories in it, would that script recurse through all of them? I seem to think with my limited recursion knowledge it would pick one 'path' down a directory tree, but I have a feeling I'm missing something. When I get on a linux system later today I'll test it heavily, replacing 'chmod's with 'echo's and see what happens. But if that works as I hoped, its immediately going in all the /usr/local/sbin folders on every box I manage
Thanks for your help guys, every solution helped me so much.
Last edited by lowpro2k3; 07-24-2005 at 12:16 PM.
|
|
|
|
07-24-2005, 01:09 PM
|
#7
|
|
Senior Member
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
|
David,
I see it now, thanks for explaining. BTW, very elegant recursion.
|
|
|
|
07-24-2005, 08:15 PM
|
#8
|
|
Moderator
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,505
Rep: 
|
Quote:
Originally posted by archtoad6
David,
I see it now, thanks for explaining. BTW, very elegant recursion.
|
Thanks. That's the first time any of my code has been called elegant, so I take that as quite a compliment.
|
|
|
|
07-25-2005, 10:34 AM
|
#9
|
|
Senior Member
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
|
You're welcome.
Of course, Humble Programmer (tm  ), that I am; I still like my "Alexandrine" approach for its speed & simplicity, in spite of the brute force aspect of it -- changing everything & fixing the deliberate mistakes.
|
|
|
|
07-25-2005, 02:18 PM
|
#10
|
|
Moderator
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,505
Rep: 
|
Quote:
Originally posted by lowpro2k3
I haven't had a chance to run the script yet, but I think thats exactly what I'm looking for. I forgot the '$0' was the name of the script in bash, very nice.
Quick question, if a top level directory (say /usr/local/apache/htdocs) had multiple directories in it, would that script recurse through all of them? I seem to think with my limited recursion knowledge it would pick one 'path' down a directory tree, but I have a feeling I'm missing something. When I get on a linux system later today I'll test it heavily, replacing 'chmod's with 'echo's and see what happens. But if that works as I hoped, its immediately going in all the /usr/local/sbin folders on every box I manage 
Thanks for your help guys, every solution helped me so much.
|
I actually found one additional bug, corrected below. I've also enclosed the output of a test run on one of my directories (new source tree for something I'm writing).
Code:
#!/bin/bash
MYDIR="."
if [ -n "$1" ]
then MYDIR=$1
fi
for file in $MYDIR/*
do
if [ -f "$file" ]
then
echo chmod 644 $file
elif [ -d "$file" ]
then
echo chmod 711 $file
$0 $file
fi
done
Output:
Code:
chmod 711 rrtower/CVS
chmod 644 rrtower/CVS/Entries
chmod 644 rrtower/CVS/Repository
chmod 644 rrtower/CVS/Root
chmod 644 rrtower/CVS/Template
chmod 711 rrtower/data
chmod 711 rrtower/data/CVS
chmod 644 rrtower/data/CVS/Entries
chmod 644 rrtower/data/CVS/Repository
chmod 644 rrtower/data/CVS/Root
chmod 644 rrtower/data/CVS/Template
chmod 711 rrtower/docs
chmod 711 rrtower/docs/CVS
chmod 644 rrtower/docs/CVS/Entries
chmod 644 rrtower/docs/CVS/Repository
chmod 644 rrtower/docs/CVS/Root
chmod 644 rrtower/docs/CVS/Template
chmod 711 rrtower/scripts
chmod 711 rrtower/scripts/CVS
chmod 644 rrtower/scripts/CVS/Entries
chmod 644 rrtower/scripts/CVS/Repository
chmod 644 rrtower/scripts/CVS/Root
chmod 644 rrtower/scripts/CVS/Template
chmod 644 rrtower/scripts/mkfile.sh
chmod 644 rrtower/scripts/setup.sh
chmod 644 rrtower/types.h
Delete the "echo" before each chmod when you are satisfied with its function. 
As you can see, it does cycle through each subdirectory and handle each of them. After the recursive call ($0 $file) it returns to the parent process to move on to the next $file.
|
|
|
|
07-25-2005, 05:14 PM
|
#11
|
|
Senior Member
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
|
The echo's are a nice touch!
How about this:
Code:
#!/bin/bash
E='echo'
# uncomment next line when you are satisfied w/ the output
#E=':'
MYDIR="."
if [ -n "$1" ]
then MYDIR=$1
fi
for file in $MYDIR/*
do
if [ -f "$file" ]
then
$E chmod 644 $file
elif [ -d "$file" ]
then
$E chmod 711 $file
$0 $file
fi
done
I have used the tecnique before, just hope I got the details right.
|
|
|
|
07-25-2005, 07:03 PM
|
#12
|
|
Moderator
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,505
Rep: 
|
also quite effective. I have many scripts where I can set an environmental variable (SIMULATE) and it echos rather than runs.
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 02:27 AM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|