-2

I would like to have a directory mydir with empty content, but I don't know in advance if it already exists, or when it does, if it is empty. So my way is

mkdir -p mydir                                                                                                           
rm -f mydir/*

Is there any flaw? What is your better solution?

6
  • 1
    If it already exists, should it be cleared out, or fail? What if you don't own it and it's not empty?
    – Jeff Schaller
    Commented Jan 9, 2016 at 20:26
  • Have you seen unix.stackexchange.com/a/84980/117549 ?
    – Jeff Schaller
    Commented Jan 9, 2016 at 20:28
  • @Cyrus how about -rf for any subdirectories of mydir?
    – Jeff Schaller
    Commented Jan 9, 2016 at 20:28
  • 1
    You could use bash constructs too, like if [ -d mydir ] && [ ! $(ls -A mydir 2>/dev/null) ]; then...
    – Kira
    Commented Jan 9, 2016 at 20:32
  • I suggest: rm -rf mydir; mkdir mydir. @JeffSchaller: I forgot option -r.
    – Cyrus
    Commented Jan 9, 2016 at 20:35

2 Answers 2

3

The flaw is that you're using an automated forced removal of a directory—and of course to remove its contents you'd need an automated forced recursive removal of a directory. You're opening yourself up to security holes in your script.

For instance, check out the --one-file-system flag for rm. You probably wouldn't want to remove all the files in any filesystems mounted within mydir...so you would have to include that flag (which has no abbreviation by the way).

Also, what about bind mounts? (See man mount and search for bind.) Those would be files technically on the same filesystem...how would rm -rf handle those? Would it delete them all? That's probably not what you wanted, but to be sure you would have to research it out and test the behavior of rm in relation to bind mounts. There are probably many many other edge cases that I didn't think of.

All this trouble comes about because you don't really want to "remove a directory and its contents"; what you actually want is to have an empty directory to work in.

There's a general principle here—when you specify something other than what you specifically want, because you think that's a route to get what you want, you are usually introducing needless complexity. The thing to do is to find how to specify what you want and then specify that explicitly.*


The better solution, as Jeff Schaller already pointed out in the comments, is to use mktemp, which is actually designed for this purpose. Specifically, from man mktemp:

Create a temporary file or directory, safely, and print its name.

The simplest use of mktemp to create a directory would look like this:

mydir="$(mktemp -d)"

Then you could copy a file into it like so:

cp somefile "$mydir/"

At the end of your script, when you're all done with the directory, you can safely remove it (and whatever you've put in it) by using:

rm -rf "$mydir"

*Another example of this principle is the use of sed commands to handle field-based or column-based files. You may be able to do it...but you can specify exactly what you want by using awk, and with much less complexity.

3
  • w/ sed you can do it faster, more specifically, and more flexibly. coming from one who has never understood awk, i would also argue your complexity statement - regexp is very basic. but it is also actually a mathematical equation. i dunno if you can get more exact than that.
    – mikeserv
    Commented Jan 10, 2016 at 4:39
  • 1
    @mikeserv, it's actually funny to me that you claim that sed is "more flexible" but in the same breath admit to never having understood awk. That's like saying that machine code is "more flexible" than Perl or Lisp (without learning either), because "Perl and Lisp have to be turned into machine code anyways before they are executed by the CPU." awk was designed to handle field-based data and it is excellent for that purpose.
    – Wildcard
    Commented Jan 10, 2016 at 11:21
  • but that's what regular expressions do - they define matched fields. And anyway, I breathed twice. And yeah, I don't understand awk - it's way too complicated. I like simple expressions - I like to balance equations. Regular expressions work that way inherently with primitives that build and compound. That's simple. awk is a gigantic scripting language - it abstracted and confounded every which way. It is far from simple. sed is more flexible in that it gives you a direct interface to the system's regex libs. You call the shots, not the syntax.
    – mikeserv
    Commented Jan 10, 2016 at 11:42
-1

mkdir fails because it should. That's a good thing. A failing command is a command that is working. It's correctly returning to you a testable error code. And so the simple thing to do is test it.

:& cd -P "${TMPDIR:-/tmp}" || exit
x=$(((z=($$+$!)/2+1000)-1001))
until mkdir -m a=,u=rwx "work.$0.$((x+=1))" &&
      cd -- "work.$0.$x"
do    [ "$x" -lt "$z" ]    || ! break
done  2>/dev/null          &&
WORK=$PWD exec 9<.
4
  • 3
    -1 because this is not the "simple thing to do." I pray I never have to maintain code written like this.
    – Wildcard
    Commented Jan 10, 2016 at 11:14
  • @Wildcard - written like what? It's a group of 7 self-evident lines that either obtains a secure temporary working directory and returns true or it doesn't and returns false. What do you think it does?
    – mikeserv
    Commented Jan 10, 2016 at 11:16
  • 3
    "...7 self-evident lines..."—If I hadn't read so many of your answers, I would think that this was trolling. But I do think you honestly believe it. There's no point in discussing it with you when you're so set in your ways. I'll just say this: mydir="$(mktemp -d)" could be explained to a kid in grade school in about 30 seconds. Your "self-evident" code requires vast knowledge in excruciating detail about the inner workings of the shell before it's even possible to guess what it does, let alone prove its correctness. Code clarity and code maintainability does have value.
    – Wildcard
    Commented Jan 10, 2016 at 11:31
  • @Wildcard - it says: cd tmpdir || exit; until mkdir && cd work; do x -lt z || ! break; done && work=$pwd. It doesn't involve piped data or prngs. There is no inherent difficulty with specific unix systems, or failure to find a command. Can you explain those things to the third grader? In my opinion, that's stuff he ought to know.
    – mikeserv
    Commented Jan 10, 2016 at 11:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .