What you're asking for doesn't make much sense in the general case, so it's not surprising that find
has no provision for it.
A symlink with a relative target is relative to the path of the symlink. So for instance, if by traversing a directory by following symlinks, find
encounters a/b/c/d
and a
, a/b
, a/b/c
are all relative or absolute symlinks (or symlinks to paths with symlink components), what should it do?
If you're looking for a find
predicate or a GNU -printf
%
directive that expands to a symlink-free path to the file relative to the current directory or any directory, I'm afraid there's none.
If you're on Linux, you can get the absolute path of those files with:
find -L foo -type f -exec readlink -f {} \;
As you found out, there exists at least one realpath
command which accepts more than one path argument which in combination with the standard -exec cmd {} +
syntax is going to be a lot more efficient since it's running as few realpath commands as necessary:
find -L foo -type f -exec realpath {} +
find -L foo -type f -print0 | xargs -r0 realpath
might be quicker as if more than one realpath
command is needed, find
can keep on looking for more files while the first realpath
starts working which even on a single processor system might make it more efficient.
-print0
and xargs -r0
are not standard, come from GNU but are found in a number of other implementations like most modern BSDs.
Zsh has builtin support for it:
print -rl foo/***/*(-.:A)
If you don't care about the sorting order, you can disable sorting and make it a bit more efficient with:
print -rl foo/***/*(-.oN:A)
If you want to convert those to relative paths to the current directory, you could have a look at that SO question.
If you know that all those files have an absolute canonical path (whose none of the components are symlinks) inside the current directory, you can simplify it to (still with zsh
):
files=(foo/***/*(-.:A))
print -rl -- ${files#$PWD/}
Though short and convenient, and works whatever character filenames contain, I doubt it would faster than find
+ realpath
.
With the Debian realpath
and GNU tools, you can do:
cd -P .
find -L foo -type f -exec realpath -z {} + |
gawk -v p="$PWD" -v l="${#PWD}" -v RS='\0' -vORS='\0' '
substr($0, 1, l+1) == p "/" {$0 = substr($0, l+2)}; 1' |
xargs -r0 whatever you want to do with them
As I realise now, there's now a realpath
in recent versions of GNU coreutils, which has the exact feature you're looking for, so it's just a matter of
find -L foo -type f -print0 |
xargs -r0 realpath -z --relative-base . |
xargs -r0 whatever you want to do with them
(use --relative-to .
instead of --relative-base .
if you want relative paths even for files whose symlink free path doesn't reside below the current working directory).
Best Answer
UPDATE: I've added a new (different) script...
Ignacio Vazquez-Abrams
had a point: The question really asks forexecutable scripts are green, et cetera
.. okay... you'll find such a (prototype) script at the end of this answer.This first (original) section is about
grc
andgrcat
.This should work;
grc
... (as enzotib has pointed out.. The package name isgrc
... The sub-utility used in the example, isgrcat
The following example prints
./
in magentabin/cpp/
in cyanbigint
in bold whiteI haven't fully sorted out how it handles it config file yet, but this looks like it will do what you want (once you tame it).. eg. for a file with no sub-dir, and the color sequence seems to not be in the same sequence as the expressions.
I assume it is possible (but I'm a bit busy at the moment)...
Here is the new Ignacio inspired script :)
This works if you use a single path as the first arg to
find
.There are UNTESTED issues in this script. It is only concept.
One issue is: Symbolic Links... murky waters...
As-is, it prints an
ERROR
when it encounters an unknown type (eg. a symbolic link), and then continues processing past that.Thanks to
enzotib
for thetput
examples.