shellcheck icon indicating copy to clipboard operation
shellcheck copied to clipboard

SC2124 warns even for single-element array range assignments.

Open deryni opened this issue 8 years ago • 6 comments

#!/bin/bash

a=(1 2 3 4)

f=${a[@]:1:1}

: "$f"

The above warns about SC2124 on the f assignment but that assignment is selecting a set of elements of length 1.

deryni avatar Oct 18 '15 21:10 deryni

Out of curiosity, did this come up in real code?

koalaman avatar Oct 31 '15 21:10 koalaman

It came up in code I actually wrote. How "real" that code is you can judge for yourself. =)

https://github.com/deryni/expandTilde.sh/blob/master/tildeExpand.sh#L36

Looking at it again there's no reason not to just use * there instead but @ is my default as it is almost universally more useful.

And actually, looking at this again I notice that when run on the tests.sh file in that repository SC2088 only triggers on the three lines with ~ by itself and not the other lines where ~ is used for other expansions. (And I did just find a comment about people not using the ~user/ uses in another filed issue and while I generally agree with you it is actually useful in very specific situations. We've found some for it at work recently.)

deryni avatar Nov 01 '15 01:11 deryni

this has come up in Google with people trying to slice off the last element:

config="${@: -1}"

technically the lint warning is incorrect here, although from a style pov, i can see people arguing that you should stick to $* to be consistent and avoid further confusing people who aren't great with shell code.

here's some test data:

#!/bin/bash

# should warn
var="${@}"
var="${@: -2}"
var="${@: -2:2}"
var="${@:1}"
var="${@:1:2}"
var="${@:2:-2}"
var="${@:$i}"
var="${@:1:$i}"

# arguably should not warn
var="${@: -1}"
var="${@: -1:1}"
var="${@: -2:1}"
var="${@:1:1}"
var="${@:2:-1}"

# pathological
var="${@:1:0}"

# silence unused warnings
export var

i can't think of a scenario off the top of my head where a count of 0 would make sense.

vapier avatar Jul 10 '17 20:07 vapier

I would argue that it should warn.

${@:1:1} is not a single element. It's between 0 and 1 elements, inclusive.

${*:1:1}, meanwhile, is exactly 1 element. If the parameter is undefined, it's the empty string.

It might warrant a separate warning explaining this though. This would additionally allow you to disable it if you're so inclined.

koalaman avatar Jul 10 '17 21:07 koalaman

when it comes to variable assignment, the distinction doesn't matter. but when it comes to arguments, it does, although shellcheck doesn't flag this.

#!/bin/bash
set --
[ "${@:2:1}" = "a" ]

this suffers from under quoting and it really should be "${*:2:1}" for that reason.

vapier avatar Jul 11 '17 04:07 vapier

Even worse, ${var[index]} and ${var[@]:index:1} are not synonyms even for assignment.

It turns out that ${var:start:length} has a surprising quirk:

x=(alpha bravo charlie delta)
unset 'x[1]'
y="${x[1]}"
z="${x[@]:1:1}"
echo "${y:-Yvoid}" "${z:-Zvoid}"

You might expect Yvoid Zvoid, but no, the output is Yvoid charlie.

kurahaupo avatar Sep 03 '22 05:09 kurahaupo