[Discussion] ls mode
On exa's website I describe exa as being a replacement for ls, rather than, say, an alternative. I think this has ruffled the feathers of a few people who read "replacement" more strictly than I do! And they have a point: you can't replace /bin/ls with exa and expect all your scripts to continue working, because they're fundamentally incompatible. exa makes trade-offs, such as colours and my preferred defaults, knowing full well that the ubiquitous ls binary will still be around if you need it.
However, we can narrow this gap by introducing ls mode: a way for exa to behave like ls, making it a true replacement.
How to use it?
Some ideas for how this mode would be activated:
- Detecting that the name of the binary is
lsrather thanexa. This isn't quite without precedent: GNUtrueandfalsepull this trick. - Adding another environment variable, like all "rarely-used" options, like
EXA_LSor something. (Where would you put it, though? If you put it in your shell config, then use it in scripts, your shell might not load the right config file and you'd get confused.) - A command-line argument like
--lsthat would be checked for and removed before doing any of the others. This is actually already done for--helpand--verbose, which override all other options.
Which ls to target?
The biggest problem with doing this is that there are multiple, incompatible versions of ls! The version I have on my Mac, from the BSD userland, uses -G for colourised output; the version I use on Linux, from GNU coreutils, wants me to use --color. The sorting parameters are different. The ways to control non-ASCII characters aren't the same, and scripts are likely to use those. And there are two versions of LS_COLORS to support. (I'm already behind on one.)
And this is just two OSes, not counting all the ones I haven't heard of where exa is slightly incompatible. If you use exa in place of ls, and it's not 100% compatible, then you might as well just use ls, right?
My stance
I think I convinced myself against this idea while writing the previous paragraph.
I want exa to have all of ls's features, even if it doesn't have the same options, and having an ls compatibility layer would be a way to ensure that those features are there. One recent addition was --all --all, to list the . and .. directories: ls just does this with --all. If exa needed to emulate ls, it would need to emulate this behaviour too, and for that to happen, it needs to have this feature implemented.
Anyway, I'd like to open this up for discussion — this issue might be open for a while!
I agree with your stance that exa should stay oriented towards the user rather than scripts.
If you were to implement an ls mode at all, I would choose the --ls switch. Checking the name of the binary isn't a good idea in my opinion because I often like to have exa in my ~bin where who knows what it might really be named. (I just have aliases over l, la, ll etc.)
Another thought might be that exa could just forward the call / passthrough to a real ls binary instead of handling it itself. If there's a "real" ls in the path (which -a ls) then exa could just call that instead. (But that would mean detecting if the other lss in the path are secretly exas or not.)
That idea doesn't cover the case in which there's no other ls on the system, but most commonly I keep exa in my home area.
How are other people using exa?
Just to talk about my use case - I just basically alias ls=exa (with some options I like to have on by default) and use it like that. I have no problem realizing it's a different program with different options, but I don't think I used ls's more advanced functionality enough for it to really affect me. My muscle memory is so trained on typing ls, and exa is similar enough that I decided I'd just use exa as a replacement instead, and "learn" anything that might be different from ls.
i need to show number of files within each directory somewhere, i see there's no flag for that. how would one go about that, should I just pipe it to wc -l ? output is not valid for number of files in this case.
@cycle337 I think the recommended / portable way to do that would be to use find and count instead. Even ls output is often discouraged to be used in scripts...
as per tldp the way to do it is to pipe it first through grep and invert match on starting with d and then pipe to wc -l. such hassle. so bore
Nobody should be using ls in scripts anyway. For interactive use alias is enough. Nobody in their right mind replaces grep with ag/rg, for example. I don't think introducing ls-mode is worth time and effort spent on it.
ls also lists the . and .. entries using the -A flag. Is this something that you would consider adding? I have trained myself to type ls -Ahl while navigating, and am having a difficult time unlearning this behaviour.
This is pretty easy to do with clap and symlinks, even to the point of having entirely different options between "ls mode" and regular exa. It's also unaffected by aliases, so alias ls=exa wouldn't trigger "ls mode".
Whether or not it's a good idea, or just introduces more confusion is another topic. I see exa a "moder day successor" to ls, rather than replacement. Now if exa does something faster, or better than ls practically speaking, I would say it's a good candidate for a feature like this because ideally you would want people to be able to replace/phase out ls. If it's simply a user facing, modern replacement with sane defaults and nice colors, I'd be less inclined to see something like this because it could introduce confusion when there isn't a 1:1 functionality parity.
If you decide this is still something to implement anyways, based on all the things I've worked on in the CLI space I would recommend either the symlink or environment variable are the way to go. I think the --ls flag will end up being far more pain than it's worth, and possibly introduce subtle bugs.
So I came to this issue by way of wanting to report/request that -t work the way it does in 'ls'. My basis is that I, and I suspect a lot of other users, have muscle memories. It looks like #89 was moving us toward the idea of being able to have some defaults that would let us do some emulation of existing behavior. I understand both sides of this argument, but added this because I didn't see the value of "muscle memory" mentioned above.
The biggest problem with doing this is that there are multiple, incompatible versions of ls!
If that is the concern, why not target POSIX ls? This would surely be the the most portable choice.
Sorry for reviving an old ticket, I'm asking out of curiousity more than anything
I am in @bexelbie's camp - I fully enjoy exa (which I have aliased to ls) except for every single time my fingers type ls -lrt and then I have to backtrack and type ls -lsnew. It would be great to make this behave the same as in ls. Note: I am slowly reeducating myself, but 20+ years of muscle memory don't go away easily :)
To be honest I’ve only ever see complaints about -t and -A, so I believe implementing/fixing those two flags for compatibility with exa is enough for the vast majority of people.
➜ l -rt
exa: Flag -t needs a value (choices: modified, changed, accessed, created)
To sort newest files last, try "--sort newest", or just "-snew"
I have so much in my muscle memory to sort files by modified date, so I think I have to ditch the idea of having alias ls=exa
actually it's
ls is aliased to `exa --group-directories-first -I Icon'
@glensc I made this wrapper script which makes the switches as close to ls as possible, reverses sorting, etc.
https://gist.github.com/eggbean/74db77c4f6404dd1f975bd6f048b86f8
Sharing an alternative approach of a small wrapper/shim that supports arguments commonly passed to ls.
When passing arguments that are not enumerated, a reminder is output to stderr to use \ls or exa directly (so definitely add additional cases for the arguments you commonly use).
Although this approach requires matching the arguments order, it is not tied to a specific ls flavor. This works for me since I always type the arguments the same way and I am able to copy this script onto various OS systems confidently (modifying/adding/removing cases as needed).
ls2exa()
{
if ! command -v exa >/dev/null 2>&1
then
echo "Command \`exa\` not found." >&2
return 1
fi
case "$1" in
-lA)
exa -g -la "${@:2}"
;;
-la)
exa -g -laa "${@:2}"
;;
-*)
echo "Usupported arguments ('$1') passed to \`ls2exa\` shim. Use \`\\ls\` or \`exa\` instead." >&2
return 2
;;
*)
exa -- "$@"
;;
esac
}
alias ls="ls2exa"
P.S. And as mentioned in earlier comments, aliases such as l, ll, la, lx, lt, tree, etc. are great too since the aliases can simply use the appropriate exa command arguments directly.