Bash – How to list files in reverse time order by a command and pass them as arguments to another command

argumentsbashdatefiles

I have a program which takes in some files as arguments in one command line. I would like to invoke it with all the files in a directory listed in reverse time order.

For example:

I have following files in reverse time order in a directory

$ ls -tr
 Introduction.pdf  'Object-Oriented Data Model.pdf' 

I can run my program straightforward,

myprogram Introduction.pdf  'Object-Oriented Data Model.pdf' 

but I want to do the file listing by another command. This won't work because of the space in one file's name:

myprogram $(ls -tr)

I remember parsing ls output is not a good practice. I am not sure if find can help.

What can I do then?

Thanks.

Best Answer

If you've got reasonably up-to-date versions of the GNU utilities you can have them handle NULL-terminated data. This allows one to construct pipelines that are not affected by whitespace or newlines in the data itself.

My test tool is a quick script called /tmp/args:

#!/bin/bash
echo "This is args with $# value(s)"
for f in "$@"; do echo "> $f <"; done

This is how you can feed it a series of filenames on the command line, sorted by file time last modified:

find -type f -printf "%T@ %p\0" | sort -zn | sed -z 's/^[0-9.]* //' | xargs -0 /tmp/args

The find command prefixes each file/path name with a representation in fractional seconds of the date/time last modified. This is handled by sort to order from lowest (oldest) to highest (newest). The sed strips off the leading number we've just used to sort by, and the resulting set of filenames are passed to xargs. Replace the %p with %P if you prefer to omit the leading ./ from filenames.

Example data

# "c d" contains a space; "e f" contains a newline; "h" has leading whitespace
touch a 'e
f' g ' h ' 'c d' b

Example result

This is args with 6 value(s)
> ./a <
> ./e
f <
> ./g <
> ./ h  <
> ./c d <
> ./b <
Related Question