Using GNU coreutils on iterm2 disables LSCOLORS - gnu

I am using iterm2 on Mac OS Catalina, however, I prefer all the GNU utils over the FreeBSD ones. Specifically, the cp command in FreeBSD lacks the -t option to specify the target, which I like to use when piping find | xargs cp -t <dest>.
So I used brew to install the GNU core utils as described in this post: https://apple.stackexchange.com/questions/69223/how-to-replace-mac-os-x-utilities-with-gnu-core-utilities
And so, I now have the GNU versions of the common shell tools, my ls is now using the /usr/local/opt/coreutils/libexec/gnubin/ls. The downside is that my ls colors are now gone. See below:
env and command outputs
I can obviously get around this by aliasing my ls command with the /bin/ls but I am wondering if there is a better way. How can I get the GNU ls to recognize my environment settings for colors?

You need to use dircolors to change the coreutil ls output. This link has details on how to use it. https://www.gnu.org/software/coreutils/manual/html_node/dircolors-invocation.html

I had the same issue.
Looks like all GNU ls needed was --color=auto
So this alias in my .zshrc worked -
alias ls='ls -G --color=auto'
I assume the same should work in .bashrc (not tested).

Related

How to validly add linux command option at the end?

I am wondering how I can add linux command option at the end without error.
For example
rm file1/ -r
cp file1/ file2/ -r
I experience some Linux cluster system can do it, bus others cannot.
As searched for while, getopts command may help but I am not sure if getopts is best choice for that and (also not sure how to implement for that my purpose).
Do I need to customize command by command or there is more general solution that can be applied any command?
Thank you for your help.
Consider this command:
rm -f myfile -r -- -i
The GNU flag convention is to allow options anywhere, up until an optional -- to indicate "end of options". Programs following it will see the options -r and -f, plus the arguments myfile and -i
The BSD flag convention is that flags are only allowed up until the first non-flag argument, or until an optional --. Programs following it will see the option -f, plus the arguments myfile, -r, -- and -i.
POSIX only requires utilities to support the BSD style.
It's up to the individual program to decide how to interpret flags. If you're on a BSD style system like FreeBSD or macOS, you can install GNU tools and use those. If you can't, you're mostly stuck with the system's flag convention.

Linux: Can't find expect in my /bin/ or /usr/bin after installing. How do I find it?

I realise this might be a stupid question, but I've been trying to follow the advice on the following post https://stackoverflow.com/questions/16928004/how-to-enter-ssh-password-using-bash
However, I've come up to a problem. I installed expect with sudo apt-get install expect but now embarrassingly I can't figure out where the script interpreter is. It doesn't seem to be in the normal paths where people look to (i.e /bin/ or /usr/bin/ ).
It does seem to have installed, since $ expect seems to work, but I just can't use the interpreter (i.e I try to shebang it like everyone else with #!/bin/sh/expect and it gives an error).
You can find the location by listing all the files the package expect provides by dpkg -L:
dpkg -L expect
or narrow it down to only the filenames ending in expect:
dpkg -L expect | grep '/expect$'
or if resides in typical binary directories:
dpkg -L expect | grep -E '/s?bin/'
Also the typical way to go through the $PATH for an executable is to use:
which expect
or better (considering shell internals), not strictly needed in this case though:
type -a expect
whereis expect
... (you could have guessed it ;)

How can I test my Bash script on older versions of Bash?

I'm working on a Bash library and want to ensure I'm supporting as many environments as possible - including old installations of Bash. My development environment is Bash 4.3, but some of my users may well be running much older versions and presently I have no way to confirm or deny that my library will work for them. In particular I'd like to be compatible with OSX (which still ships with Bash 3.2, AFAIK).
I know Bash can run in POSIX-compliant mode; is there a similar setting to disable modern functionality? Or a way to run Bash in some sort of compatibility mode? I'm looking for any technique short of actually finding and booting up old operating systems and testing my library there.
Update
For example, I've avoided using associative arrays since they were introduced in Bash 4, but it's hard to be sure without testing that I'm not accidentally using some other Bash 4+ feature.
Finally coming back to this question, it's pretty easy to just compile (without installing) the bash version(s) you're interested in. Here's how I'm testing Bash 3.2.57:
$ mkdir ~/bash
$ cd ~/bash
$ wget http://ftp.gnu.org/gnu/bash/bash-3.2.57.tar.gz
$ tar xvzf bash-3.2.57.tar.gz
$ cd bash-3.2.57
$ ./configure
$ make
# if `make` fails due to yacc, run `sudo apt-get install byacc`
# No need to run `make install`
$ ./bash -version
GNU bash, version 3.2.57(1)-release (armv7l-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
Now you have a bash 3.2.57 binary you can run, without actually "installing" it or modifying your normal environment.
To run a shell script against this version:
$ ./bash your_script.sh
To enter a clean interactive prompt:
$ env -i PATH="$PWD:$PATH" ./bash --noprofile --norc
bash-3.2$ bash -version
GNU bash, version 3.2.57(1)-release (armv7l-unknown-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
bash-3.2$
Using env -i rather than just calling ./bash directly leaves you with a mostly-empty environment (run env from inside the shell to see what's still set). Updating the PATH allows calls to bash (e.g. bash -version) to invoke the local bash shell, not the system-wide installation (but note this pulls in your whole PATH). Adding --noprofile --norc avoids loading your .bashrc and associated scripts.
If you don't want to pick up any PATH modifications, just execute export PATH="$PWD:$PATH" once inside the subshell instead of as part of the env command.
I have a Docker image (repo) using these installation steps, if that's helpful for folks to reference. I wouldn't necessarily suggest using this image directly, but you're welcome to copy from the Dockerfile/install script. MIT licensed.
Although it's nice to know that it's possible to compile arbitrary versions of bash locally (as discussed in my other answer), these days there's a much simpler option - the official Docker bash images.
To test a script against multiple bash versions is often as simple as:
for v in 3 4 5; do # or whatever versions you're interested in
docker run -v "$PWD:/mnt" "bash:$v" \
bash /mnt/your_script.sh
done
Have a look at shenv: https://github.com/shenv/shenv. Just like rbenv, pyenv, goenv and others, but for shells, it lets you install different versions of Bash among others (zsh, fish, yash, etc.).
(Disclaimer: I'm the one who forked pyenv into shenv!)
You can use Bash own facilities to emulate older version of Bash. Look up "compat" options on shopt.
Mind you, while it does change behavior as described under each compatNN entry in the man page, it does not remove features that are otherwise present on the current version. For example, this doesn't cause any errors:
shopt -s compat31
shopt -s globstar
Even though globstar was only introduced on Bash 4.0.

How to make zsh `run-help` to ignore `sudo` and get help about the following command

Is it possible to customize zsh so that when I type, say, sudo ls and then hit Alt-h to see man page of the command ls. The default behavior of run-help is to show me the man page of the command sudo, instead of ls.
Yes, you can. Run the following lines or add them to your .zshrc.
autoload -U run-help
autoload run-help-sudo
from zsh wiki:
[run-help] can be further customized by defining helper functions of
the form run-help-command.
There are other helper functions, as of version 5.0.8:
run-help-git
run-help-ip
run-help-openssl
run-help-p4
run-help-sudo
run-help-svk
run-help-svn
If you are running a Debian, you can find all helper functions function by:
dpkg -L zsh-common | grep run-help

different behavior of which command in zsh and bash

By using zsh for some time along with oh-my-zsh framework, I noticed that which command behaves different in zsh, than in bash.
What I mean:
# on zsh
ilias#ilias-pc ~ ➜ which ls
ls: aliased to ls --color=auto
ilias#ilias-pc ~ ➜ which which
which: shell built-in command
ilias#ilias-pc ~ ➜ bash
[ilias#ilias-pc ~]$ which ls
/usr/bin/ls
[ilias#ilias-pc ~]$ which which
/usr/bin/which
[ilias#ilias-pc ~]$
Why does this happen and how can I "fix" it?
PS. I reproduce this on Arch Linux (not sure whether it matters but I mention it).
$ zsh -c 'type which'
which is a shell builtin
$ bash -c 'type which'
which is /usr/bin/which
The solution is to not use which(1), which is a non-standard and not very useful command. The question of what you should use instead isn't the most straightforward due to the alternatives being poorly specified and inconsistently implemented, but they are better than which.
Depending on your requirements, you want command (see the -v option), type, or whence. See POSIX for the former two, or your shell manual for the latter. (Bash doesn't support whence, but it is supported by most other ksh derivatives, albeit inconsistently. It typically has the most features).
In ZSH, which is equivalent to whence -c (showing function's definitions), not whence -p (which tells executable path). If you want to change that, make an alias.

Resources