In your first example, grep should not be re-sorting the filenames you pass to it. If you are passing them explicitly, it will print the output in the same order as the list of files you pass it. However, if you are passing a wildcard, you are correct that your shell will expand that wildcard in lexical order (which is basically what ls defaults to, as you noted).
After looking at the other suggestions, I offer the following:
file=`ls -t --quoting-style=shell "dir" | xargs grep -l "regex" | head -n 1`
I think this meets your requirements, and addresses concerns raised by others as follows:
- You can use
ls -t without -l, so there's no need to parse the output of ls -l with awk or cut just to get the filename.
- Don't reverse the sort order of
ls. Using ls -t puts the newest files first, and grabbing the first one with head will short-circuit the pipeline as soon as the first matching file is found (so you search the minimal list of files necessary to find a match).
- Piping to
xargs effectively lets you search an unlimited number of files without running into the maximum command line length, and does so without looping.
- Using
ls --quoting-style=shell quotes filenames with single quotes as needed, so filenames with embedded spaces or control characters are handled properly.
Please note that --quoting-style is a GNU extension and is not likely to work with a non-GNU ls. You should be fine on Linux. The following is more portable, but adds a call to sed to quote the filenames, so there's a little more overhead:
file=`ls -t "dir" | sed 's/\(.*\)/"\1"/' | xargs grep -l "regex" | head -n 1`