0

I want to shorten this to a one liner:

if ls --version 2>/dev/null | grep -q 'coreutils'; then alias ls='ls --color=always'
else alias ls='ls -G'
fi

I frequently use [] for conditionals, e.g. [ -z(or -n) condition] but haven't had to do an else part in this format yet.

In ruby I would do condition ? true : false Is there an equivalent in bash?

I tried

[ -z ls --version 2>/dev/null | grep -q 'coreutils'] ? alias ls='ls --color=always' : alias ls='ls -G'

but obviously that's not the right way to do it.

I want a one-liner because I want all my .bashrc to fit in a smallish window (< ~50 lines) so, as with other multi-liners I condense them into one liners when possible. I am comfortable with sacrificing readability for size for this example.

I also tried:

[ -z ls --version 2>/dev/null | grep -q 'coreutils'] && alias ls='ls --color=always' || alias ls='ls -G'

and

[ -n ls --version 2>/dev/null | grep -q 'coreutils'] && alias ls='ls --color=always' || alias ls='ls -G'

and

[ ls --version 2>/dev/null | grep -q 'coreutils'] && alias ls='ls --color=always' || alias ls='ls -G'

but I always get the 'else' alias not the 'then' alias

I could just reverse it but I suspect that as it's not working right that wouldn't help. Only way to be sure though is to try it on OSX and I'm on ubuntu right now.

2 Answers2

2

tl;dr;

Use

ls --color=always > /dev/null 2>&1 && alias ls='ls --color=always' || alias ls='ls -G'`

Details....
[...] are only needed to evaluate conditional expressions (stats of files, string comparisons, numeric comparisons; see CONDITIONAL EXPRESSIONS in bash(1)). They would also be needed for that in a if ... ; then ...; else construct.

For relatively simple constructs

if CONDITION; then
    EXPR1
else
    EXPR2
fi

can be replaced by

CONDITION && EXPR1 || EXPR2

If you do not need [...] in the first case, you do not need it for the second.

In your case CONDITION is ls --version 2>/dev/null | grep -q 'coreutils', that is the return code of grep. So you can just write

ls --version 2>/dev/null | grep -q 'coreutils' && alias ls='ls --color=always' || alias ls='ls -G'

BTW: It would be easier to check if ls supports --color directly:

ls --color=always > /dev/null 2>&1 && alias ls='ls --color=always' || alias ls='ls -G'
Adaephon
  • 4,456
  • Not just for arithmetic - eg http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html – Josh Jolly May 10 '14 at 13:26
  • @JoshJolly Thanks for the catch, it should of course be conditional expressions. – Adaephon May 10 '14 at 13:36
  • 1
    Note that you should only use that (and IMO, it's better not to use that at all) if you can guarantee that EXPR1 will always return true as otherwise EXPR2 will also be executed. – Stéphane Chazelas May 10 '14 at 15:10
1

With zsh, it can be compressed to:

if {ls --version|&grep -q coreutils} {alias ls='ls --color=always'
} else {alias ls='ls -G'}

The cmd1 && cmd2 || cmd3 construct as a replacement for if/then/else should generally be avoided as it's not the same at all.

In

cmd1 && cmd2 || cmd3`

cmd2 is executed if cmd1 returns true. And cmd3 is executed if either of cmd1 or cmd2 returns false.

In your case cmd2 (alias) is very unlikely to return false, but it's easy to forget about the problem in the general case, so it's best to avoid that construct in the first place.

The only real reason where it may be useful is when you want to write code that works in both Bourne-like and csh-like shells (or rc-like ones where that works as well) where the if/then/else construct have different syntax.