-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SC2230 - command -v is not a direct replacement for which #1162
Comments
You could use 'pwd'. 'which' is not posix but it sure seems common to me.. where is it not? |
For example: $ which if
# exits nonzero
$ command -v if
if
# exits zero
$ foo() { true ; }
$ which foo
# exits nonzero
$ command -v foo
foo
# exits zero |
https://github.com/koalaman/shellcheck/wiki/SC2230 See: "SC2230 - command -v is not a direct replacement for which #1162" koalaman/shellcheck#1162
Besides that, |
So do we think that this check should be removed? |
👍 I would favor removal. |
which can be replaced with type -p, |
An alternative to type -P ls
/bin/ls |
While which can certainly be used if a user decides to (they can easily ignore the shellcheck warning, the argument 'but it is so common and always available' is of course moot and opinionated (yes, even busybox features it these days). The point remains, if you use /bin/sh you kind of imply POSIX compliance, and even if not, some of us would still like this warning to be triggered. Just as which not being standard (again, even with being so ever common). As with everything, there are exceptions of course. But I think this is not one of them, the exception should be in your code or your parser, where you globally or locally ignore this test as that would work for you. (You being not the individual personal you). A fair improvement of course would be to the wikipage, for users who run into this, get noted of this. While surely there are a few valid usecases, I was thinking a bit more about this, and from a users point of view, I can imagine the difference "will this command work in my script (command -v) vs what is the path of this utility (which)". Sometimes a user may be interested only where the binary is, rather then whether it will work. My earlier thoughts still remain the same, but the wiki surly needs clarification of this exceptional case.
I suppose a decent workaround would be: |
This is a example where #!/bin/bash
tooling=( bash no_such_command )
# shellcheck disable=2230
which "${tooling[@]}" &> /dev/null || echo some tools are missing
command -v "${tooling[@]}" &> /dev/null || echo some tools are missing Hence, |
is this even supposed to work? check_requirements()
{
for cmd in ${CMDS}; do
if ! test_result="$(command -V "${cmd}")"; then
test_result_fail="${test_result_fail:-}${test_result}\n"
else
test_result_pass="${test_result_pass:-}${test_result}\n"
fi
done
echo "Passed tests:"
# As the results contain \n, we expect these to be interpreted.
# shellcheck disable=SC2059
printf "${test_result_pass:-none\n}"
echo
echo "Failed tests:"
# shellcheck disable=SC2059
printf "${test_result_fail:-none\n}"
echo
if [ -n "${test_result_fail:-}" ]; then
echo "Self-test failed, missing dependencies."
exit 1
fi
} which yes, is a lot longer, but also is a lot friendlier to the user imo :) so yeah, which can do this in one line, but just because you can, doesn't mean you should imo :) |
Yes,
So, you advocate to maintain 15+ LoC that triggers far more concerning checks instead of a single one that just has a "non-standard tool" warning? Thank you, but no. However, the main issue here is saying that things are interchangeable when they aren't. Following the advice in this check can break perfectly working code. |
Fair point, which does the same in one go, which is indeed (no pun intended) admittedly quite nice. So at the least, the wording could be improved absolutely. But the fact remains, and the warning, that it is a non-standard tool. So a green warning should be sufficient.
nod |
I've found out another difference between
Therefore I think the suggestion should be replace |
The problem is that For a PR that added the one more reason (for me) to not use
|
Feel free to use, integrate in your projects, adapt, expand my Bash Implementation of the This is the minified version which-min.sh, that is 455 bytes versus 946 bytes for the native version: #!/usr/bin/env bash
IFS=:;if (($#>0))&&[ "${1:0:1}" == - ];then if [ "$1" != -a ];then printf >&2 'Illegal option %s\nUsage: which [-a] args\n' "$1";exit 2;else b=1;fi;shift;fi;read -rd '' -a g < <(printf %s:\\0 "$PATH");while (($# > 0));do f=0;for d in "${g[@]}";do e="$d/$1";while [[ -L $e && "$(ls -l "$e")" =~ -\>\ (.*) ]];do e="${BASH_REMATCH[1]}";done;if [[ -f $e && -x $e ]];then f=1;echo "$d/$1";((b))||break;fi;done;((f))||c=1;shift;done;exit $c The human readable non-minified version is here: which.sh. |
I just lost about 40 minutes debugging this one, assuming I'd introduced the error alongside quoting fixes around some alias commands that I made at the same time. I'm still vaguely glad the issue came up--I realized I could at least swap The current language is quite confident, and I naively took it at face value. |
The fundamental problem with Here's an excellent background on the topic by the always virtuose @stephane-chazelas: |
Shellcheck requires the shell to be specified with #! so non-standard shells can be treated independently of sh/bash. |
Shellcheck's web page, states:
It says that it finds bugs it doesn't say anything about portability. If finding bugs is the goal, then shellcheck should keep quiet about people on Bash using Shell check probably needs to beef up its logic to handle differences between major shells - for instance Also, I didn't see anyway to specify the shell version - I suppose we should presume a recent version but it would be nice if shellcheck displayed what version of a shell it was running against. |
I use shellcheck mainly in my Visual Studio Coder extension, where shellcheck issues are neatly listed in the "Problems" console. However:
|
In vim shellcheck lists Errors, and Warnings.
|
It's the right thing to do in this context. See koalaman/shellcheck#1162 for more info. Signed-off-by: Gerhard Lazu <gerhard@lazu.co.uk>
Apparently this check defaults to off since 0f15fa4 was released in 0.7.1. |
I tried suggesting a little more lint-like categories a while ago. It would be nice if the numbering scheme followed something like error (1000), warning (2000), info (3000), portability (4000), and best-practice/stye (5000). Deploying shell check as quality tool could be done as many lint-like tools. Over time it would easier to ratchet QA checks on system scripts and supported tools. Both of these ideas were not accepted. Also |
I wonder if there's a reason not to recommend Instead, there are mentions about |
I've found a somehow portabel solution working on IBM AIX, msys2 and RHEL7. $ alias grep=true
$ command -v grep
alias grep=true
$ which grep # on IBM AIX
/opt/freeware/bin/grep
$ which grep # on RHEL7
alias grep='true'
/usr/bin/true
$ whence grep # on IBM AIX
true
$ whence grep # on RHEL7 and msys2
-bash: whence: command not found
$ type -P grep
/usr/bin/grep
$ type -P grep # on IBM AIX
ksh: whence: 0403-010 A specified flag is not valid for this command.
$ sh -c "command -v grep" # working on all |
A minor note on the above: the reason 'whence' appears to only work on IBM AIX, is that 'whence' is a korn shell built-in, and ksh is the default shell on AIX. On RHEL7, the default shell is bash, which does not have the 'whence' built-in. For example, if you were to use ksh on RHEL7, 'whence' would also work. And if you were to use bash on AIX, 'whence' would also fail. The difference is not really OS related, but shell related instead. |
For bugs
shellcheck --version
or "online"): 4.4.7 (latest from git)Here's a snippet or screenshot that shows the problem:
Here's what shellcheck currently says:
In test.sh line 3:
which "$0"
^-- SC2230: which is non-standard. Use builtin 'command -v' instead.
In test.sh line 4:
/usr/bin/which "$0"
^-- SC2230: which is non-standard. Use builtin 'command -v' instead.
Here's what I wanted or expected to see:
Because "command -v" does not do the same as which, I would have liked to see nothing.
When running the above (from /tmp), I get:
/tmp/test.sh
/tmp/test.sh
./test.sh
While "which" may not be standard, it is commonly used to get the full path.
At the very least I would like to not get warned when I specifically use the path as in the third command - then it's fairly certain what the user wants, which won't be the common bash alias.
The text was updated successfully, but these errors were encountered: