Syntax for rm command

  • Posted: 12 November 2011 11:27 AM

    Hello Gabbers!

    I am struggling to formulate the right syntax with rm.

    - I have a folder called Archives, which contains 50 or so folders that are named by date (e.g. /Nov1, /Nov2, /Nov3, ...).
    - Within each of those folders are several folders, named /Folder1 and /Folder2

    Here’s what I want to do:

    I want rm to recursively search through /Archives and all subfolders and remove all instances of /Folder1 and /Folder2

    I tried this but it wasn’t a pretty outcome:

    sudo rm -r /Volumes/SSDclone/Archives Folder*

    Where did I go wrong?

    Thanks,
    Tim

         
  • Avatar

    Posted: 15 November 2011 03:09 PM #1

    Quick answer:

          sudo rm -r /Volumes/SSDclone/Archives/*/Folder[12]

    The first problem is that if you have a space in a pathname on the command line, it needs to be escaped. The problem is that if you just put the whole thing in quotes, it will also escape the *, which shouldn’t be escaped.

    The other problem is that you aren’t mentioning the subfolder of Archives.

    Turns out that because you don’t have any spaces in your folder names, you don’t need to worry about escaping any. The * matches all the Nov1, Nov2, etc, folders, and the [12] will match either the character 1 or 2 (therefore, Folder1 or Folder2). So this will match all Folder1’s and Folder2’s inside any folder inside /Volumes/SSDclone/Archives/

    What do you do if the volume is “SSD clone” instead of “SSDclone”

    Easy answer: cd there and sudo rm -r Archives/*/Folder[12]

    Other answer:

    sudo rm -r /Volumes/SSD\ clone/Archives/*/Folder[12]

    The \ before the space escapes it, so it doesn’t tread “/Volumes/SSD” as one item to be removed (that would be bad if that actually existed!) and “clone/Archives/*/Folder[12]” as the other.

    Things getting dicier:

    What if instead of simple folders like Nov1 and Nov2, you had Folder1 both at that level, or lower?

    Best approach there is to use find. And at that point, I would cd into the top directory where you might find these:

    cd /Volumes/SSDclone/Archives
    sudo find . -type d -a -name “Folder[12]” -print0 | xargs -0 rm -r

    Here you are putting Folder[12] in quotes. Why? Because otherwise it would try to find Folder1 or Folder2 in Archives, and, not finding it, give up (although bash might not). By putting it in quotes, you let find worry about the [12] (which it’s perfectly capable of doing).

    So what will find do? It will look through Archives (the current directory you’re in, or ‘.’) for entry that is both a directory (-type d) AND (-a) whose name matches the wildcard Folder[12]. Any that match get print0’d.

    What does print0 do? It prints the name of the directory on the standard output (to be picked up by the pipe (|), but all names are separated by an ASCII NULL character. Since the NULL character can not be in any file, you are guaranteed that it if you only look for paths separated by NULL, you’ll find all the paths.

    That is then piped into xargs. xargs takes it’s input and runs it’s argument command on each entry in it’s input. If you give xargs the -0 flag then it separates it’s input by ASCII NULL characters (that you gave it with the print0 in find). So xargs will do rm -r   for all the paths that find matches.

    In theory, the print0 / -0 isn’t always necessary, but since it’s available, I always use it.

         
  • Posted: 18 November 2011 05:42 PM #2

    Thanks for the really useful and detailed post!
    Best,
    Tim

         
  • Posted: 25 April 2012 08:00 PM #3

    Be careful with rm -r.  A guy I know once did this:

    rm -r * .bak

    When he meant:

    rm -r *.bak

    Of course Unix ignored everything after the *, and it deleted EVERYTHING.