18

The accepted answer to Transform an array into arguments of a command? uses the following Bash command:

command "${my_array[@]/#/-}" "$1"

I'm trying to figure out what the /#/- part does, exactly. Unfortunately, I don't know what to call it, so I'm having trouble finding any documentation. I've looked through the Bash man page section on arrays and a few websites, but can't find anything.

Justin
  • 283

2 Answers2

25

This is an instance of pattern replacement in shell parameter expansion: ${parameter/pattern/replacement} expands ${parameter}, replacing the first instance of pattern with replacement. In the context of a pattern of this kind, # is special: it anchors the pattern to the start of the parameter. The end result of all this is to expand all the values in the my_array array, prepending - to each one (by replacing the empty pattern at the start of each parameter).

Stephen Kitt
  • 434,908
3

Yes, it is a pattern replacement in shell parameter expansion as:

${parameter/pattern/replacement}

But if the first character after the first / is either / or # or % it has the special meaning of all (repeated), start and end.

with:

$ str='one_#two_two_three_one'

A single / will replace the first instance. The first instance of one:

$ echo "${str/one/x-x}"
x-x_#two_two_three_one

Or the first instance of two:

$ echo "${str/two/x-x}"
one_#x-x_two_three_one

The instance of one at the end:

$ echo "${str/%one/x-x}"
one_#two_two_three_x-x

All repetitions of two:

$ echo "${str//two/x-x}"
one_#x-x_x-x_three_one

The instance of one at the start:

$ echo "${str/#one/x-x}"
x-x_#two_two_three_one

An string that start with # (quote the #):

$ echo "${str/\#two/x-x}"
one_x-x_two_three_one

But if you leave the # (unquoted) alone, the replacement is set at the beginning of the variable:

$ echo "${str/#/====}"
====one_#two_two_three_one

Furthermore, if the parameter is an array, the replacement is done on all elements:

$ str=( one two three )
$ echo "${str[@]/#/==}"
==one ==two ==three
  • The wording is a bit misleading as the # and % are part of the pattern while // is a different operator from / and use the same patterns. You can have pattern='#x'; echo "${var/$pattern}" (or ${var//$pattern}), but pattern=/x; echo "${var/$pattern}" is not the same as echo "${var//x}". Note that # and % can be combined in zsh, but not bash nor ksh. – Stéphane Chazelas Oct 06 '18 at 22:23