views:

544

answers:

6

How do you exclude a folder when performing file operations i.e. cp etc.

I would currently use the wild card * to apply file operation to all, but I need to exclude one single folder.

The command I'm actually wanting to use is chown to change the owner of all the files in a directory but I need to exclude one sub directory.

+2  A: 
for file in *
  if [ $file != "file_I_dont_want_to_chown" ]
    then
      chown -R Camsoft $file
  fi
done 
danben
You don't need `ls`. Just use `for file in *`
Dennis Williamson
Thanks, made the change
danben
A: 

Combine multiple small sharp tools of unix: To exclude the folder "foo"

% ls -d * | grep -v foo | xargs -d "\n" chown -R Camsoft
Christopher Bruns
Would that work recursively, drilling down in to sub-directories?
Camsoft
The `-0` here accomplishes nothing.
Dennis Williamson
It will work recursively now that I added the "-R".
Christopher Bruns
I'm getting an "File name too long" error when executing the above command. The filename shown in the error seems to be a concatenation of all the files in the directory separated with "\n"
Camsoft
That's because `ls` is not intended to be used this way.
Dennis Williamson
'-d "\n"' might help. I'm not on a linux box at the moment, so I can't be certain. It works with cygwin.
Christopher Bruns
@Dennis Williamson: actually, it's probably because of the `-0`
Hasturkun
+5  A: 

If you're using bash and enable extglob via shopt -s extglob then you can use !(<pattern>) to exclude the given pattern.

Ignacio Vazquez-Abrams
I've executed the command above. Can you give me an example that uses the !() syntax in combination with chown?
Camsoft
`chown 0755 -R !(foo)`
Ignacio Vazquez-Abrams
That worked! One more question will the excluded filename be applied recusively, so that if there is a folder or file called foo deeper in the directory tree will that one also be skiped too? I only want to exclude the first foo which is a direct descendent of the top level folder.
Camsoft
Only if you use a pattern such as `**/foo`.
Ignacio Vazquez-Abrams
So like: chown 0755 -R !(**/foo) ?
Camsoft
Correct, although `**` requires the `globstar` shell option to be enabled (which only exists in bash 4.0), and it doesn't contain foo, so you'd need `chown 0755 -R !({foo,**/foo})`.
Ignacio Vazquez-Abrams
This works for me on Ubuntu 10.04 LTS and also CentOS5. I first run that shopt command, cd into the dir I want to adjust, and then run chown with the NOT condition. Works like a charm. Really cool hack!
Volomike
A: 

Another option might be to temporarily remove permission on the that file /folder.
In Unix you need 'x' permission on a directory to enter it.

edit: obviously this isn't goign to work if you are backing up a live production database - but for excluding your 'interesting images' collection when copying documents to a USB key it's reasoanable.

Martin Beckett
Unfortunately the directory I want to exclude is a certs folder and messing the permissions of this up will break our HTTPS requests.
Camsoft
Fair enough - it's just sometimes the solution is simpler than a complex regex/xargs statement ;-)
Martin Beckett
+2  A: 
find dir_to_start -name dir_to_exclude -prune -o -print0 | xargs -0 chown owner

find dir_to_start -not -name "file_to_exclude"  -print0 | xargs -0 chown owner
Dennis Williamson
+1  A: 

For this situation I would recommend using find. You can specify paths to exclude using the -not -iwhilename 'PATH'. Then using exec you execute the command you want to execute

find . -not -iwholename './var/foo*' -exec chown www-data '{}' \;

Although this probably does help for your situation I have also see scripts set the immutable flag. Make sure you remove the flag when your done you should use trap for this just in case the script is killed early (note: run from a script, the trap code runs when the bash session exits). A lot of trouble in my option but it's good in some situations.

cd /var
trap 'chattr -R -i foo > /dev/null 2>&1' 0
chattr -R +i foo
chown -R www-data *
mholzmann