LinuxQuestions.org
Did you know LQ has a Linux Hardware Compatibility List?
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
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



Reply
 
Search this Thread
Old 07-23-2005, 09:59 PM   #1
lowpro2k3
Member
 
Registered: Oct 2003
Location: Canada
Distribution: Slackware
Posts: 340

Rep: Reputation: 30
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.
 
Old 07-24-2005, 02:14 AM   #2
Tinkster
Moderator
 
Registered: Apr 2002
Location: in a fallen world
Distribution: slackware by choice, others too :} ... android.
Posts: 23,004
Blog Entries: 11

Rep: Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903Reputation: 903
Code:
#!/bin/bash
find -type d -exec chmod 711 {} \;
find -type f -exec chmod 664 {} \;


Cheers,
Tink
 
Old 07-24-2005, 02:34 AM   #3
Matir
Moderator
 
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,507

Rep: Reputation: 118Reputation: 118
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
 
Old 07-24-2005, 07:18 AM   #4
archtoad6
Senior Member
 
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
Blog Entries: 15

Rep: Reputation: 231Reputation: 231Reputation: 231
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.)
 
Old 07-24-2005, 12:41 PM   #5
Matir
Moderator
 
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,507

Rep: Reputation: 118Reputation: 118
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
 
Old 07-24-2005, 01:14 PM   #6
lowpro2k3
Member
 
Registered: Oct 2003
Location: Canada
Distribution: Slackware
Posts: 340

Original Poster
Rep: Reputation: 30
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 01:16 PM.
 
Old 07-24-2005, 02:09 PM   #7
archtoad6
Senior Member
 
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
Blog Entries: 15

Rep: Reputation: 231Reputation: 231Reputation: 231
David,

I see it now, thanks for explaining. BTW, very elegant recursion.
 
Old 07-24-2005, 09:15 PM   #8
Matir
Moderator
 
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,507

Rep: Reputation: 118Reputation: 118
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.
 
Old 07-25-2005, 11:34 AM   #9
archtoad6
Senior Member
 
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
Blog Entries: 15

Rep: Reputation: 231Reputation: 231Reputation: 231
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.
 
Old 07-25-2005, 03:18 PM   #10
Matir
Moderator
 
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,507

Rep: Reputation: 118Reputation: 118
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.
 
Old 07-25-2005, 06:14 PM   #11
archtoad6
Senior Member
 
Registered: Oct 2004
Location: Houston, TX (usa)
Distribution: MEPIS, Debian, Knoppix,
Posts: 4,727
Blog Entries: 15

Rep: Reputation: 231Reputation: 231Reputation: 231
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.
 
Old 07-25-2005, 08:03 PM   #12
Matir
Moderator
 
Registered: Nov 2004
Location: San Jose, CA
Distribution: Ubuntu
Posts: 8,507

Rep: Reputation: 118Reputation: 118
also quite effective. I have many scripts where I can set an environmental variable (SIMULATE) and it echos rather than runs.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
chmod recursive on files on dlublink Linux - Newbie 6 03-02-2005 09:45 AM
recursive yet selective chmod bluefire Linux - General 6 10-22-2004 07:25 PM
chmod.....recursive help stateq2 Linux - General 3 03-28-2004 08:28 PM
modify bash script - recursive action xscousr Programming 6 09-17-2003 02:52 PM
Messed up recursive with chmod Cyth Linux - General 4 01-03-2003 01:16 PM


All times are GMT -5. The time now is 11:50 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration