Como usar pseudo-arrays no script de shell POSIX?

5

Eu não consigo entender:

Como usar pseudo-arrays no script de shell POSIX?

Eu quero substituir uma matriz de 10 inteiros em um script Bash com algo similar ao script de shell POSIX.

Consegui encontrar truques sh (POSIX shell) do Rich , na seção Trabalhando com matrizes .

O que eu tentei:

save_pseudo_array()
{
    for i do
        printf %s\n "$i" | sed "s/'/'\\''/g;1s/^/'/;\$s/\$/' \\/"
    done
    echo " "
}

coords=$(save_pseudo_array "$@")
set -- 1895 955 1104 691 1131 660 1145 570 1199 381
eval "set -- $coords"

Eu não compreendo isso, esse é o problema, se alguém pudesse lançar alguma luz sobre isso, muito apreciado.

    
por Vlastimil 01.02.2018 / 10:06

2 respostas

8

A idéia é codificar a lista de strings arbitrárias em uma variável escalar em um formato que possa ser usado posteriormente para reconstruir a lista ou cadeias arbitrárias.

 $ save_pseudo_array x "y z" $'x\ny' "a'b"
'x' \
'y z' \
'x
y' \
'a'\''b' \

$

Quando você coloca set -- na frente disso, ele cria um código de shell que reconstrói essa lista de x , y z strings e a armazena na matriz $@ , que você precisa apenas de eval uate .

O sed cuida de citar corretamente cada string (adiciona ' no início da primeira linha, no final da última linha e substitui todos os ' s por '\'' ).

No entanto, isso significa executar um comando printf e sed para cada argumento, por isso é bastante ineficiente. Isso poderia ser feito de uma forma mais direta com apenas uma invocação awk:

save_pseudo_array() {
  LC_ALL=C awk -v q=\' '
    BEGIN{
      for (i=1; i<ARGC; i++) {
        gsub(q, q "\" q q, ARGV[i])
        printf "%s ", q ARGV[i] q
      }
      print ""
    }' "$@"
}
    
por 01.02.2018 / 10:17
7

A ideia básica é usar set para recriar a experiência de trabalhar com valores indexados de uma matriz. Portanto, quando você quiser trabalhar com uma matriz, execute set com os valores; isso é

set -- 1895 955 1104 691 1131 660 1145 570 1199 381

Em seguida, você pode usar $1 , $2 , for etc. para trabalhar com os valores fornecidos.

Tudo isso não é muito útil se você precisar de vários arrays. É aí que entra o truque save e eval : a função save processa os parâmetros posicionais atuais e gera uma string, com a cotação apropriada, que pode ser usada com eval para restaurar os valores armazenados. Assim você corre

coords=$(save "$@")

para salvar a matriz de trabalho atual em coords , criar uma nova matriz, trabalhar com ela e quando precisar trabalhar com coords novamente, você eval it:

eval "set -- $coords"

Para entender o exemplo, você deve considerar que está trabalhando com dois arrays aqui, aquele com valores definidos anteriormente e armazenado em coords , e o array contendo 1895, 955 etc. O próprio fragmento não Não faz muito sentido sozinho, você teria algum processamento entre as linhas set e eval . Se você precisar voltar para o array de 1895, 955 mais tarde, salve o primeiro antes de restaurar coords :

newarray=$(save "$@")
eval "set -- $coords"

Dessa forma, você pode restaurar $newarray depois.

    
por 01.02.2018 / 10:16