Como posso prefixar e anexar a cada membro de uma matriz?

5

Eu tenho uma matriz:

CATEGORIES=(one two three four)

Eu posso prefixar a cada membro da matriz usando a expansão de parâmetro:

echo ${CATEGORIES[@]/#/foo }

Eu posso acrescentar a cada membro da matriz da mesma maneira:

echo ${CATEGORIES[@]/%/ bar}

Como posso fazer as duas coisas? Nenhum desses trabalhos:

echo ${CATEGORIES[@]/(.*)/foo  bar}
echo ${CATEGORIES[@]/(.*)/foo $1 bar}
echo ${CATEGORIES[@]/(.*)/foo ${BASH_REMATCH[1]} bar}
    
por David Kennedy 23.05.2015 / 03:26

4 respostas

5

Dependendo do seu objetivo final, você pode usar printf :

$ a=(1 2 3)
$ printf "foo %s bar\n" "${a[@]}"
foo 1 bar
foo 2 bar
foo 3 bar

printf reutiliza a string de formato até que todos os argumentos sejam usados, portanto, fornece uma maneira fácil de aplicar alguma formatação a um conjunto de strings.

    
por 23.05.2015 / 03:38
5

Para o registro, com zsh , há o operador ${^array} que ativa a expansão parecida com a chave nos elementos da matriz. Então:

$ a=(one two three)
$ b=('foo '${^a}' bar')
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>

Pesquisar e substituir também funciona em zsh .

$ printf '<%s>\n' ${a//(#m)*/foo $MATCH bar}
<foo one bar>
<foo two bar>
<foo three bar>

Além de printf -v em uma matriz:

$ b=(); printf -v b 'foo %s bar' "$a[@]"
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>

Seu echo ${CATEGORIES[@]/(.*)/foo bar} funcionaria em ksh93 se escrito como:

$ printf '<%s>\n' "${CATEGORIES[@]/@(.*)/foo  bar}"
<foo one bar>
<foo two bar>
<foo three bar>
    
por 23.05.2015 / 23:51
4
p='* "foo  '
s='  bar $USER' 
CATEGORIES=(one two three four)
CATEGORIES=("${CATEGORIES[@]/#/$p}")
CATEGORIES=("${CATEGORIES[@]/%/$s}")

paste <(printf '[%s]\n' "${!CATEGORIES[@]}") \
      <(printf '%s\n'    "${CATEGORIES[@]}")

Saída:

[0] * "foo  one  bar $USER
[1] * "foo  two  bar $USER
[2] * "foo  three  bar $USER
[3] * "foo  four  bar $USER
    
por 23.05.2015 / 10:13
1

Aqui está uma solução de caso especial que é adequada quando a string anexada (ou prefixada) é um caractere único , e você não precisa dos valores em uma nova matriz :

array=( aa bb cc )
IFS="]"                        # or, IFS="["
echo "${array[*]/#/ [}$IFS"    # or, echo "$IFS${array[*]/%/] }

que produz saída [aa] [bb] [cc] .

  • o formulário citado "${array[*]}" adiciona o separador ] entre cada par (o primeiro caractere de IFS , é onde as restrições surgem)
  • ${array[*]/#/ [} adiciona [ a cada elemento (ou /%/ forma a acrescentar)
  • finalmente, adicione um ] (de IFS ) à direita para o valor expandido

Se essas etapas forem aplicadas uma a uma, você terá:

aa]bb]cc
 [aa] [bb] [cc
 [aa] [bb] [cc]

(Você também pode recuperar os dados trivialmente como uma nova matriz se os valores não contiverem espaço em branco.)

Você pode fazer as operações distintas de prefixo / postfix em um one-liner:

for ii in "${array[@]/#/foo }"; do echo "${ii/%/ bar}"; done

Esta é uma solução printf mais robusta que copia para uma nova matriz:

mapfile -d '' newarray < <(printf "foo %s bar
declare -a array newarray   # -a for indexed array, -A for associative
array=( one two three )
for ii in "${!array[@]}"; do
  printf -v "newarray[$ii]" "foo %s bar" "${array[$ii]}"
done
" "${array[@]}")

embora às custas de um subshell (bash-4.4 requerido para mapfile -d )

Finalmente, uma variação de loop que copia para uma nova matriz e também lida com matrizes esparsas e associativas, se necessário.

array=( aa bb cc )
newarray=( "${array[@]/*/foo & bar}" )

( printf não é necessário, você pode atribuir diretamente, mas é mais claro IMHO. bash não (ainda!) suporta impressão em uma matriz, mas zsh faz, dando-lhe uma cópia sem loop e transformar one-liner, veja a resposta de Stéphane acima.)

O que seria útil aqui é se bash suportasse o% comum& (como $MATCH in zsh ) como um marcador de lugar para a sequência combinada em expansões. O código está lá (e tem sido há muito tempo), mas infelizmente ainda não está ativado (veja shouldexp_replacement() em subst.c ). Se você ativá-lo (duas #if 0 alterações e recompilar), isso funciona como esperado:

compgen -P "foo " -S " bar" -W "${array[*]}"

Não importa, talvez esteja disponível na próxima versão ...

compgen tem uma operação de prefixo / sufixo (e suporta & , mas não de uma forma que possamos usar aqui). O melhor que podemos fazer com isso não é tão bom quanto a solução printf de um muru:

array=( aa bb cc )
IFS="]"                        # or, IFS="["
echo "${array[*]/#/ [}$IFS"    # or, echo "$IFS${array[*]/%/] }

(note -W leva apenas uma única opção, então a matriz é nivelada, e isso causa problemas com valores com espaços ou qualquer coisa em IFS )

    
por 23.02.2018 / 18:51