find
interprets a dash at the start of a filename as the start of an option. Using the familiar --
trick doesn't work since options are after the filename, quoting has no effect, and replacing the first dash with \-
doesn't work either. Users are often encouraged to precede such filenames with ./
, but what can I do if I don't know whether the given path will be absolute or relative?
Edit: One solution is to find "$(readlink -f -- "$test_filename")"
, but it's ugly. Any better ideas?
Edit 2: Thanks for the suggestions. Here are the two scripts that resulted from this effort: safe-find.sh; safe-count-files.sh
Here is a way that should work on all Unix-like systems, with no requirement on a specific shell or on a non-standard utility¹.
If you have a list of directories in your positional parameters and want to process them, it gets a little complicated. Here's a POSIX sh solution:
Bourne shells and other pre-POSIX sh implementations lack arithmetic and
set --
, so it's a little uglier.¹
readlink -f
is available on GNU (Linux, Cygwin, etc.), NetBSD ≥4.0, OpenBSD ≥2.2, BusyBox. It is not available (unless you've installed GNU tools, and you've made sure they're in yourPATH
) on Mac OS X (as of 10.6.4), HP-UX (as of 11.22), Solaris (as of OpenSolaris 200906), AIX (as of 7.1).Use a glob to capture the dash:
edit: updated to remove the phrase regular expression, and to quote the glob so it's interpreted by find, not bash (only affects some edge cases).
If it is in a script you can always check for it. E.g. for bash, ksh or zsh:
In a more terse form (for bash, ksh93 or zsh):
You can even do this with the parameters of a script, if they are all supposed to be directories:
This may seem a bit cheap, but I actually recommend the
readlink
workaround that you've figured out. According to the Unix standard,so
--
will indeed not work. thkala's solution may also work, but I find it less readable. It may be faster though, if you're doing a lot offind
invocations.