6

I have ZSH as my primary shell, and I'm trying to randomise access to an array. I keep seeing feh called, but I don't have that command. I have _feh, but I don't know if it's the same thing. What is that command.

Here's the reference:

FILES=( .../files/* )
feh $FILES[$RANDOM%$#FILES+1]

Here is my testing:

test=(a b c); feh ${test[$RANDOM]}

I'm on OSX 10.10.x for reference. Ultimately I'll use this to randomise SSH access to some hosts that I have.

0

2 Answers 2

8

feh is an image viewer, just ignore that part... you want just the second part.

Basically, to access a random array element you want something like ${arr[${ri}]} where ri is $(( $RANDOM % ${#arr[@]} + 1)) that is, ri is a random index of the array arr

Now, $RANDOM % N resolves to a random number from 0 to N-1. In this case N is the array length ${#arr[@]} (number of elements) but since array indexing starts from 1 in zsh you have to add one ( + 1) so that $(( $RANDOM % ${#arr[@]} + 1 )) returns a value from 1 to N.

So e.g. to print a random element of the array:

print -r -- ${arr[$(( $RANDOM % ${#arr[@]} + 1 ))]}

Or simply, as array indices are parsed as arithmetic expressions:

print -r -- "$arr[RANDOM % $#arr + 1]"

When using that csh-style syntax (when the expansion is not in braces), the quotes are necessary in order for zsh to parse the subscript; alternatively, this could be written $arr[RANDOM%$#arr+1] or ${arr[RANDOM % $#arr + 1]} (ksh-style).

2
  • Is that last part still correct, about array indices parsed as arithmetic expressions? I get a "invalid subscript" error.
    – Michaël
    Oct 20, 2020 at 5:10
  • 1
    @Michaël, see edit. Dec 23, 2020 at 10:25
1

Another approach is to shuffle the array. Here, for an array that is the result of a glob expansion that can be done with:

files=( .../files/*(noe['REPLY=$RANDOM']) )
feh $files # or $files[1]

Or

shuffle() REPLY=$RANDOME
files=( .../files/*(no+suffle) )

To shuffle an arbitrary array, one technique is to still use the oe or o+ glob qualifier, with something like:

shuffled_array=( /(e['reply=("$array[@]")']no+shuffle) )

That is use the e qualifier to make up the glob expansion (here applied to /) by setting $reply there, and then sort it with o+.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.