Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is there a simple way to evaluate what a given rm command will do when you do not understand it (such as not recognizing how the flags, variables, etc. interact)?

While ls helps catch problems in your rm parameters, ls -abc XYZ does not list the same files that would be affected by rm -abc XYZ. Ideally, I would like to type something like previewrm -abc XYZ and see what would be removed without actually removing anything, including using the -f flag.

I essentially want to run rm in test batch mode. That is, I want to see what actions it would take if it was run for real, preferably without touching it at all. Thus, testout 'rm -abc XYZ' might be the true ideal.

share|improve this question
4  
echo rm -abc XYZ shows you which files and directories will be directly affected. Do you want to see the directory contents? Or do you want to know what cannot be deleted (due to access rights)? –  Hauke Laging Mar 18 at 22:19
    
Ideally, I would like to see directory contents and also how access rights affect the outcome, but echo does meet some of the need. It catches things like rm $FOO/* and rm *(1)*. –  user63051 Mar 18 at 22:34
    
If you want to run rm in test batch mode, i.e. showing what actions it would take if it was run for real (which is what I think you want) then you should say so more explicitly. Two people have suggested rm -i, which I don't think does what you want. –  Faheem Mitha Mar 18 at 22:35
    
The answers suggesting the -i flag are the best I've seen before. I recognize that they might be the best answer there is, but my hope was for something that didn't require touching the flags. While I'm smart enough to pull out the -f, I'm looking to avoid slip-ups like rm -i -f. That is, adding the -i flag is not sufficient; you also have to pull the -f and --force. –  user63051 Mar 18 at 22:39

5 Answers 5

You could use rm -i to be prompted for every single file it will remove. You can pipe no into it repeatedly, (confusingly) using the yes command, to just view prompts (rejecting all of them):

yes no | rm -i files/globs/options

EDIT in response to comments by @user63051

If you are concerned about dangerous flag combinations, you can specify rm -i -- and anything after that will NOT be treated as an option. This of course means that for the -r flag to work, you need to put it before --.

Another suggestion, if you want to try it, is to create a dummy user that doesn't belong to any of the existing groups. If the others permissions of your files don't include write permission (they usually don't unless you specifically want that), you can just login as the other user (su dummy) and do the rm command. It won't have permissions to delete anything so it will simply complain about it. You can also do this to use the suggestion above (as double protection).

I should warn you that all the options that call rm are a bit dangerous. I usually just prefix the entire command I want to run with echo to see what arguments will bash give to the command (how it expands the wildcards and which files it finds). Then just remove echo if everything looks fine. Notice that this won't list contents of recursively found files with -r but you will see the directory it want's do destroy.

In essence - use echo if you want to see what it does. Use -- for protection from runaway flags. Use -i just in case, it will ask about every file and you will notice if it asks about something you don't want to remove. Only if you really want to produce a list, one file per line, it makes sense to do anything else.

share|improve this answer
6  
yes no has to be the most humorous command I've seen today... –  MathematicalOrchid Mar 19 at 10:02

If not using the -r option, then you can list the files with

ls -ld <parameters>

or your favorite combination of ls options, as long as it includes -d. The discrepancy between the command line arguments and what ls shows is that if one of the arguments is a directory, ls shows its contents.

If you just want to list the names, echo <parameters> will do, or if you prefer them on separate lines:

printf '%s\n' <parameters>

This list is ambiguous in case a file name contains a newline; this is a concern for automated processing but not when you know that the files weren't produced by a potentially hostile party.

If using the -r option, call find to traverse the directories recursively:

find <parameters>
share|improve this answer

Use the i switch. See man rm:

-i   prompt before every removal
share|improve this answer
    
man answers are the best answers. Simple, and verifiable. It always makes more sense to me to ask the computer what it knows than to ask the internet what my computer knows. –  mikeserv Mar 18 at 23:01
3  
@mikeserv Of course, nowadays the Internet does know what your computer knows... :) –  jasonwryan Mar 18 at 23:08
    
Probably the NSA is hip anyway. I'll give you that. –  mikeserv Mar 18 at 23:08
    
I'm sure my question is unclear, but I definitely check man before asking questions, and I was hoping for a way to preview rm results without having to touch the flags, in part so that I can copy-paste the flags+parameters without relying on myself to accurately add and remove flags in each direction. –  user63051 Mar 19 at 13:25
    
@user63051 The whole point of the -i switch, as I see it, is that your don't have to reissue the command... –  jasonwryan Mar 19 at 16:28

The simple way is to use rm -i the way @orion describes. If you want something that will not remove anything but doesn't tweak rm's flags, you can always build your own version of rm, let's call it preview-rm. It's really pretty straightforward, and you can even do it without touching the actual rm source files:

  1. Find the source to your system's version of rm. You may need to download a source package, or whatever. GNU rm is part of the "core utilities" and consists of two C files, rm.c and remove.c, and several header files. Once you are set up to compile system utilities, the rest is trivial.

  2. Create the file mockrm.c with the following contents. The only non-trivial part is that some versions of rm detect directories by trying to unlink() them and checking for error, so we need to ensure this works correctly:

    #include <stdio.h>
    #include <sys/stat.h>
    #include <errno.h>
    
    int unlink(char *s)
    {
        struct stat sbuf;
        lstat(s, &sbuf);
        /* Simulate unlink error if we're asked to unlink a directory. */
        if (S_ISDIR(sbuf.st_mode)) {
            return EISDIR;
        }
    
        puts(s);
        return 0;
    }    
    
    int rmdir(char *d)
    {
      printf("%s (dir)\n", d);
      return 0;
    }
    
  3. Finally, compile your preview-rm executable like this:

    % cc rm.c remove.c mockrm.c -o preview-rm
    

    The functions in mockrm.c will be linked in precedence to the system calls provided by the C library, giving you a toothless clone of rm that you can use for preview. (Do test that it really works before you point it at important files.)

Alternative: If you're on a system that supports the LD_PRELOAD feature (OS X doesn't), you might be able to get the same effect by compiling mockrm.c into a shared library (.so) and forcing it to be loaded by the real rm:

% LD_PRELOAD=/path/to/mockrm.so rm -flags files

But since you need to change the command invocation anyway, why not just create a separate executable as shown above. I know it'd be a little nervous pointing the real rm at valuable files (Edit: and if you update your OS, you'd have to test again and make sure rm hasn't changed in a way that disabled the wrapper.)

share|improve this answer
1  
Relying on all versions of rm to use no OS functions other than unlink and rmdir, under all circumstances, seems very unwise. I might trust that, if the utility came from the same release, from the same maintainers, as rm itself, but ONLY if I knew they also had very good QA practices. –  user17534 Mar 19 at 18:16
    
Do you know another system call that can remove a file? System calls are not designed to be redundant. But like I said, by all means inspect the source and test the result. rm (even GNU rm) is not that large a program. –  alexis Mar 19 at 18:40
    
This is the current rm source, right? lingrok.org/xref/coreutils/src/rm.c –  user63051 Mar 19 at 20:27
    
@user63051, how would I know? You haven't said which Unix distribution you are running. Your best bet is probably to get the source using your system's package manager. That said, this is not the place to find out how to do that-- it's a big topic. Look into your package manager's documentation or tutorials. –  alexis Mar 19 at 20:42
1  
@alexis: unlinkat is one such function, but that's kind of missing the point. The point is that, at any time, the implementation of rm could change, and you should not rely on it having a particular implementation, when missing any given method of implementation could be catastrophic, as is the case here. The PROPER way to solve this is to submit a patch to rm which implements a dry-run mode. The half-assed solution is to distribute your own version of rm, with a known implementation, along with a known-good wrapper for that version. Any less than that is just dangerous. –  user17534 Mar 23 at 20:06

When I want to do this, I use 'find' as a wrapper around rm. This is better (for the use case you have in mind) because:

  • It's more flexible in terms of matching multiple patterns
  • It can handle more filenames than a shell wildcard in subdirs (/.tmp etc.)
  • You can do everything rm can do, since it wraps rm, but more besides, such as printing the entire rm command.
  • It doesn't call rm too often, when you use + (rather than ;) as part of the -exec args, so it's not really much less efficient than just running rm.

To list files to you might want to delete:

find . -name \*.tmp

To preview deletion:

find . -name \*.tmp -exec echo rm \{\} +

To actually delete them, just remove the 'echo':

find . -name \*.tmp -exec rm \{\} +

Or, you can do more advanced search/delete commands, like this one:

find . \( -name \*.tmp -o -iname cache -o -iname temp \) -exec rm \{\} +

You can also just pipe the output of find into "xargs rm", but use NULs to separate filenames, like so:

find . -name \*.tmp -print0 | xargs -0 rm
share|improve this answer
    
This is definitely getting at one of my two implicit use cases. When I'm trying to be careful about what I'm removing, I might switch to using find as suggested. When I run across an rm command that I don't understand, I'll probably try the yes no | rm -i option. –  user63051 Mar 19 at 13:22

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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