With zsh
and GNU ls
:
files=(*(NDoN:P))
(($#files)) && ls -ltd -- ${(u)files}
Or with an anonymous function for brevity:
(){ (($#)) && ls -ltd -- ${(u)@}; } *(NDoN:P)
where N
enables nullglob
, D
dotglob
to include hidden files, oN
skips the sorting as ls
will sort by mtime and :P
does the equivalent of GNU readlink -f
. The (u)
parameter expansion flag removes duplicates in the array.
Or if there are so many files in the current directory that the above fails with a too many arguments errors, you can get zsh
to do the sorting and pass the list to ls -U
(to disable its own sorting, requires GNU ls
or compatible) via zargs
which like xargs
would split the list into smaller chunks if needed.
autoload zargs
files=(*(ND-om:P))
zargs -r --eof= -- ${(u)files} '' ls -lUd --
Where -om
sorts by modification time after symlink resolution.
(beware zsh
's :P
currently chokes on symlinks that have infinite loops in their resolution).
With bash
and GNU tools, you could do something approaching with:
shopt -s nullglob dotglob
files=(*)
((${#files[@]})) &&
printf '%s\0' "${files[@]}" | # prints as NUL-delimited records
xargs -r0 readlink -zf -- | # get absolute canonical path
LC_ALL=C sort -zu | # removes duplicates
xargs -r0 stat --printf '%.9Y/%n\0' -- | # get mtime with max precision
sort -rnz | # sort numerically in reverse
cut -zd/ -f2- | # remove timestamp added earlier
xargs -r0 ls -lUd -- # pass to as many ls invocations as needed
With small enough lists of files, it can be simplified to:
shopt -s nullglob dotglob
files=(*)
((${#files[@]})) &&
readlink -zf -- "${files[@]}" | # get absolute canonical path
LC_ALL=C sort -zu | # removes duplicates
xargs -r0 ls -ltd -- # pass to ls
See how we're always passing the list of files between tools as NUL-delimited records. NUL is the only character (and byte value) that cannot occur in a file path, so the only safe method.
In readlink -f * | sort
, you're passing the list of files from readlink
to sort
as newline-delimited records, so would break with filenames that contain newlines. Since you forgot the --
before *
, it would also break on filenames starting with -
.
It's a lot worse in ls -alt `cmd`
, where this time the output of cmd
is split on space, tab and newline (assuming the default value of $IFS
) and filename generation is performed on the resulting words, so it would choke on even more characters. Without -d
, ls
would also list the contents of the directories it is passed as arguments instead of just the directories themselves.
-L
flag do what you want? That'll deref symlinks. – Stephen Harris Jul 28 '20 at 01:38readlink
returns is a directory, then yourls
command will list the content of that directory. If you want to list the directory itself, you'll want to include the-d
option tols
. – Andy Dalton Jul 28 '20 at 01:41ls -alt
to the culled list. – Leo Simon Jul 29 '20 at 03:08