I'd like to make this test as fast as possible: (Bash)

if [[ -d $directory_path && -r $directory_path && -x $directory_path ]]
  • if [[ -r $directorypath ]] && ( cd $directorypath ) might be faster, if a little obscure to someone reading the script. What you gain from not doing two further tests, you lose by spawning a subshell though. – DopeGhoti Jan 13 '14 at 4:42
  • 3
    I get the feeling your asking this for some other reason? Are you looping through a bunch of directories looking at these? Why do you care how fast this is? Feels like an XY problem – slm Jan 13 '14 at 4:48
  • Not XY, I need to optimise that one-liner in a Bash script. Probably the stat, faccessat(x2) sequence. Especially the latter, as both R_OK and X_OK should be checkable in one go rather than two.. – Maroloccio Jan 13 '14 at 9:09
  • 2
    Your current solution is highly optimal for checking a single directory. The -d, -r and -x tests uses shell builtin functions. No amount of writing a special program or spawning another process is going to beat that. If, however you want to check many directories (as suggested by @XY you may have options. – Johan Jan 13 '14 at 12:00
  • Are you looking to patch bash? Perl caches the results of last stat call so you can do if (-d $dir and -r _ and -x _) – glenn jackman Jan 13 '14 at 17:31

This is as efficient as it gets.

You can see what system calls the shell makes by looking with strace (or the equivalent on unix variants other than Linux).

strace bash -c '[[ -d $directory_path && -r $directory_path && -x $directory_path ]]'
stat64("foo", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
faccessat(AT_FDCWD, "foo", R_OK)        = 0
faccessat(AT_FDCWD, "foo", X_OK)        = 0

That's almost as good as it gets. One system call to check the file type (-d), and one system call to check each permissions. While bash could try to deduce the access rights from the file mode, this would only work on systems with no access control lists.

The two calls to faccessat could be combined; neither bash nor ksh nor dash are clever enough to do that. But the gain would be minimal. The inode will be in the cache, so the cost of the repeated system calls will be extremely small. If you really needed that kind of microefficiency, you wouldn't be writing a shell script in the first place.

  • I do mention having straced already (stat, faccessat) in my comment and I have noticed the second inode read is from filesystem cache.. I guess this is already as good as it gets then. C could do better by combining R_OK and X_OK, again as I wrote in that comment.. – Maroloccio Jan 15 '14 at 14:15
  • @Maroloccio Sorry, I apparently hadn't noticed your comment. You should benchmark but I highly doubt that one system call to get information that's in cache is going to be noticeable. (On Cygwin, with an antivirus that hooks on every system call, maybe — but if that matters, go native.) Stephane does have a point though: if you're going to cd to that directory, do cd "$directory_path" && [[ -r . ]]. – Gilles Jan 15 '14 at 15:19

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.