1

I have a BASH script problem that I've narrowed down but I can't understand what I'm seeing. I want to get a substring of an array in a succinct way. Here's what I'm seeing in bash, with 'set -x' so that commands are printed as they are executed:

$: read -a colours
+ read -a colours
blue green red yellow pink purple
$: echo ${colours[@]}
+ echo blue green red yellow pink purple
blue green red yellow pink purple
$: expr substr "${colours[@]}" 16 6
+ expr substr blue green red yellow pink purple 16 6
expr: syntax error: unexpected argument ‘yellow’
$: expr substr \"${colours[@]}\" 16 6
+ expr substr '"blue' green red yellow pink 'purple"' 16 6
expr: syntax error: unexpected argument ‘yellow’

The last attempt at the expr substr command returned odd quoting for the array elements, so where did that come from? Help me understand what expr substr is doing here or is this a bug?

EDIT: I've listed below some desired behaviour on a flat quoted string, but why can't I quote an array in the same way?

$: all_colours=${colours[@]}
+ all_colours='blue green red yellow pink purple'
$: expr substr $all_colours 16 6
+ expr substr blue green red yellow pink purple 16 6
expr: syntax error: unexpected argument ‘yellow’
$: expr substr "$all_colours" 16 6
+ expr substr 'blue green red yellow pink purple' 16 6
yellow
3
  • 1
    How about using a "${colours[*]:16:6}"? If I understand you, you are trying to expand the bash array into a string, and then get its substring. I would do it on this way. I am 99% sure that "${arrayvariable[*]}" will expand it into a string. I am not sure, how can this be useful.
    – peterh
    Commented Nov 26, 2024 at 22:23
  • expr is a program used in ancient shell code to do math. This syntax has been obsolete for a few decades. In Posix shells like bash, use $(( expression )). In bash, ksh, mksh, pdksh or zsh, you can also use (( expression )) Commented Nov 27, 2024 at 2:08
  • what do you mean "odd quoting"? If you escape quotes, on the shell command line, you get literal quotes passed to the program. That's what you're doing with \"${colours[@]}\". The set -x output is shell-quoted to make it unambiguous, it just shows those arguments single-quoted. That '"blue' is the same as \"blue. (I would fully expect that when it gets to set -x printing, the shell doesn't even remember what quotes the initial command line used.)
    – ilkkachu
    Commented Nov 27, 2024 at 7:25

1 Answer 1

1

Expr is a command line tool, it is independent from the bash. It does not know anything about arrays. It gets command line arguments, exactly those what we refer as $1, $2, $3 etc in our scripts.

Important thing is: bash knows arrays, but as you call a binary, it can only get a list of arguments as its parameters.

If you call expr with an array expanded on your syntax, you will get what you said. expr substr will expect numbers, you give to it many text words, so it will complain about too much arguments and their bad type.

I am not sure, what are you trying to do with this substring - an array might have a range, or a "sub-array", or an interval but I am not sure, how you define the substring of an array.

3
  • That helps, thanks. Is there some shell expansion trick in bash to get it to pass the expanded array as a string to the expr command? Commented Nov 26, 2024 at 22:20
  • 1
    My first try would be a "${colours[*]}", so use "*" instead "@". "@" expands it into multiple params, * probably not.
    – peterh
    Commented Nov 26, 2024 at 22:24
  • "@" has a "superpower": it can break up the " around it. That is unthinkably ugly with a high level programmer eye, but very useful for a script writer. A good linuxer is a joker guy, if you are high level programmer then dont do that, if you write a script then do.
    – peterh
    Commented Nov 26, 2024 at 22:27

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.