5

Trying to find files that contains specific strings in name, but don't know how to sort output, in a way, that I will get file names only.

I've tried

OLDDATA=`find . -regex ".*/[0-9.]+" | ls -t`

But ls -t is not working on find result but on whole directory

edit: Result of this statement should be sorted by modification day directories. This regex suppose to match directories that contains only numbers and dots in name.

  • May I suggest that you explain what you think that regular expression - ".*/[0-9.]+" - should match? – ricmarques Nov 12 '17 at 16:35
  • This should match files that contains only numbers and dots in name – harcotlupus Nov 12 '17 at 16:36
7

get file names only ... sorted by modification day

find + sort + cut approach:

find . -regex ".*/[0-9.]+" -printf "%T@ %f\n" | sort | cut -d' ' -f2

  • %T@ - File's last modification time, where @ is seconds since Jan. 1, 1970, 00:00 GMT, with fractional part

  • %f - File's name with any leading directories removed (only the last element)


To sort in descending order:

find . -regex ".*/[0-9.]+" -printf "%T@ %f\n" | sort -k1,1r | cut -d' ' -f2
  • 4
    The good ol' Schwartzian transform – glenn jackman Nov 12 '17 at 18:27
  • Is there option to sort them from the newest? It worked very well, but need dates DESC – harcotlupus Nov 12 '17 at 18:51
  • @harcotlupus, see my update – RomanPerekhrest Nov 12 '17 at 18:57
5

Your method can be adapted to work in simple cases. The main problem you're facing is that you're passing input to ls, but ls doesn't take any input. ls takes command line arguments. So you need to pass the output of find as arguments to ls, with a command substitution. Also, in case a directory is matched, pass -d to ls to list the directory itself and not its contents.

OLDDATA=$(ls -td $(find . -regex ".*/[0-9.]+"))

Only in simple cases, because there are two restrictions:

  1. This relies on an unquoted command substitution (and so does the use of $OLDDATA afterwards). Therefore it assumes that the file names don't contain any special characters (whitespace or wildcard characters \[*?).
  2. Some versions of ls may mangle characters that are not printable in the current locale.
  3. If the total length of the file names is too long, you'll get an error. (Note that find … -exec and xargs cannot help here, since ls must run a single time to get the order of the file names right. All they could do is hide errors and produce output that is not correctly sorted — and mangle a few more characters, in the case of xargs.)

A robust, simple way of doing this is to use zsh. It has the ability to sort wildcard matches, thanks to glob qualifiers.

setopt extended_glob
OLDDATA=(**/[0-9.]##(om))
  • Since this doesn't call any other program, there is no length limit other than available memory, and no risk of file name mangling at any point.
  • The result is a list of strings (each string being a file name), not a string, so it goes into an array variable.
  • **/ traverses subdirectories recursively, avoiding the use of find.
  • ## means “one or more of the preceding” in zsh extended glob syntax, it's analogous to + in (extended) regex syntax.
  • (om) is a glob qualifier to sort files by modification time, like ls -t.

There is notoriously no simple way to do this robustly with POSIX tools or even with GNU tools and ksh.

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.