2

I have a few lines in a shell script whose function is to iterate through directories, match some names, and delete them. Some areas of the file system are write protected and I would like to leave those alone but redirect the prompt or some other indication of the error into a log when they are encountered.

Using rm -r /path/to/directory at that point in the script causes the script to output

rm: descend into write-protected directory /path/to/directory/subdirectory?

So it hangs and [eventually] times out when left to its own devices.

I attempted to correct this behavior by piping "n" to that prompt with

yes n | rm -rv /path/to/directory

This produces two undesired results:

  1. Outputting yes: standard output: Broken pipe; yes: write error for every directory that is removed, and
  2. Not returning the rm: descend into write-protected... message to stdout.

What is the right way to do this?

Update: According to @roaima I am not actually piping yes n to the prompt at all because the existence of that pipe makes rm non-interactive. This is ironic because I was really exploiting the interactivity just to get some output but if I turn off interactivity the program will just exit in error. I don't want to ignore the error (e.g. by appending || true as I have seen so many other places on SE) because I want the names of the protected files.

  • 2
    The message rm: descend into write-protected... is only generated by rm when it is interactive mode. By piping yes n into rm you are revoking its interactive option, so there is no longer any message to capture. – roaima Mar 3 '15 at 21:01
  • according to man, you can force interactive mode, however piping n will answer no to every file removal question, which is probably not what you want. you best try is rm -rf ( or rm -rvf ) – Archemar Mar 4 '15 at 13:05
  • @Archemar The desired result is to inform and not delete when it encounters problematic files. rm -rf will ignore them. – WAF Mar 4 '15 at 13:32
  • you still have rm: cannot remove '/my/dir/my/file.txt': Permission Denied when using rm -rf. my understanding is that you have too much of it. – Archemar Mar 4 '15 at 13:51
  • "I want the names of the protected files." - can't you get these by just seeing what files are still there at the end? – Random832 Mar 4 '15 at 15:27
2

I would suggest considering a different tool. The 'find' command is very powerful and once you get past some of the syntax rules, easy to use.

Example:

find /directory -name pattern -perm g=w -exec /bin/rm {} \;

This will search for all files and sub folders under /directory that have the group permission of 'write' (logic match to 0020 octal chmod format) It would then erase that file.

Or you can run it with the print option and get a list of what files match the find pattern.

ex: find /directory -name pattern -perm 0111 -print
  • Working through your answer now. Why do I want g=w and not u=w? (I've never used -perm before.) I will test out find but I'm afraid it might be slow. – WAF Mar 3 '15 at 19:44
  • I was just using that as an example permission, you can use any of the possible permission flags you can use with 'chmod' – Cosmo F Mar 3 '15 at 19:53
  • You should use -delete, not -exec /bin/rm. Neither g=w nor u=w works for me at all; find treats permissions differently from chmod - /=w works for this for me. – Random832 Mar 3 '15 at 21:39
  • 1
    I found it - using g=w will only find files with permission of exactly 020, rather than all files having it set. You can use -g=w or /g=w to find files with it set (-ug=w finds files with both user and group write, /ug=w finds files with either set.) – Random832 Mar 3 '15 at 21:47
  • @Random832 How will -delete behave when it encounters a write-protected subdirectory? (I am hesitant to test it before knowing.) Specifically, if I use find /directory -type d -perm /ug=w -delete will it just skip those subdirectories or will it return a message about them? What if I leave out the -perm to force the error? – WAF Mar 4 '15 at 12:47
1

rm will ask for confirmation for non-writeable targets if stdin is a terminal. The -i flag on the other hand turns on confirmation for all targets. Clearly neither works with the simple solution of piping yes n to rm, so we must use something else.

Using GNU find, delete all objects that have at least one of the write-mode bits set (as usual, use -print instead of -delete at first to test):

find dir/ -perm /0222 -delete

Or, delete all files(*) with at least one write-mode bit set, but skip the contents of non-writeable directories :

find . -type d ! -perm /0222 -prune -o ! -type d -perm /0222 -exec rm {} + 

(* actually everything but directories)

-delete implies a depth-first search (at least on GNU find), and doesn't work with -prune, so we can't use that here. We can delete empty writeable directories after that:

find . -type d -perm /0222 -delete

This will throw errors for nonempty directories.

-perm /0222 stands for "any of the write bits are set", and its inverse ! -perm /0222 for "none of the write bits are set".

In other versions of find, use +0222 instead of /0222. (According to the GNU manpage, the former conflicts with POSIX requirements and has been deprecated.)


To find the non-writeable files and directories, we can similarly use

find . ! -perm /0222 

Recursively listing the contents of non-writeable directories is a bit harder to do, but with GNU tools this might work:

find . ! -perm /0222 -print0 | xargs -0 find 
-3

First change permission of directory that you want to delete by using command :

chmod -R 777 directory/ 

and then remove directory by using command :

rm -rf directory/.
  • Hi @Rimpi and thanks for the suggestion! What the question is looking for is a way to output the name of the protected directory, not get rid of it. – WAF Dec 30 '18 at 17:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.