Use o awk para dividir a linha em array e usar os valores dessa matriz no shell de chamada

6

Estou tentando usar awk dentro de um script bash e fazer uma tarefa bastante comum: iterar linhas de arquivo bem estruturadas e dividi-las por um delimitador em uma matriz. Aqui está uma amostra do arquivo:

Joe:Johnson:25
Sue:Miller:27

Existem inúmeros exemplos de como isso pode ser feito em uma única linha no modo interativo, no entanto, estou fazendo isso em um script no qual eu gostaria de usar aquele array manipulado pelo awk fora do subshell awk no próprio bash:

cat ${smryfile} | while read smryline; do

    echo ${smryline}

    #now i want to split the line into array 'linearray' in awk but have it usable when i get back to bash
    echo ${smryline} | awk '{split($0,$linearray,":")}'

    varX=$linearray[2]
    echo $varX
    #do something with $varX

done

Eu recebo um erro:

awk: syntax error at source line 1
 context is
     >>> {split($0,$linearray <<< ,":")}
awk: illegal statement at source line 1

É possível fazer o que estou tentando fazer (usar arrays que estão definidos no awk fora de seu escopo) e como devo fazê-lo?

    
por amphibient 05.02.2014 / 22:09

3 respostas

7

Acho que você pode fazer o que quiser sem o awk:

cat "${smryfile}" | while IFS=: read first last varx
do
    echo "first='$first' last='$last' varx='$varx'"
    # do something
done

Isso produz:

first='Joe' last='Johnson' varx='25'
first='Sue' last='Miller' varx='27'

Observe que essa abordagem funcionará mesmo que alguns nomes no arquivo incluam espaços.

Note também que o uso de cat acima não é necessário:

while IFS=: read first last varx
do
    echo "first='$first' last='$last' varx='$varx'"
    # do something
done <"${smryfile}"

Um benefício colateral de remover cat , conforme o acima, é que quaisquer variáveis que você criar no loop sobreviverão após o término do loop.

    
por 05.02.2014 / 22:34
5

Isso deve funcionar:

linearray=($(awk -F: '{$1=$1} 1' <<<"${smryline}"))
echo ${linearray[2]}
# output: 27

Explicação: awk -F: divide a entrada em : . Por padrão, awk separa a saída modificada por um espaço, portanto, você pode construir uma matriz bash diretamente com a saída de awk . Anote saída modificada , daí a chamada no-op para $1=$1 , senão os dados acabariam de sair na forma original.

Mas, dado o seu exemplo, por que não extrair a terceira coluna com awk -F: e fazer um loop na saída:

awk -F: '{print $3}' "$smryfile" | while read varX; do
    echo $varX
done
    
por 05.02.2014 / 22:18
0

Com certeza você pediu uma solução com awk , mas acho que a solução sed está um pouco mais clara.

str="Joe:Johnson:25"
array=($(echo "$str" | sed 's/:/ /g'))
for el in "${array[@]}"; do
    echo "el = $el"
done

Isso dá:

el = Joe
el = Johnson
el = 25

Nesse caso, você precisa ter certeza de não colocar aspas duplas em torno da expansão de comando, para que você não fique com um único elemento de string.

E isso não funciona para elementos que contêm espaços, é claro. Se você tivesse:

str="Joe:Johnson:25:Red Blue"

Você acabaria com

el = Joe
el = Johnson
el = Red
el = Blue

Mas se você não se importa em usar eval , você pode inserir aspas antes da atribuição da matriz para fazê-lo funcionar.

eval "array=($(echo "\"$str\"" | sed 's/:/" "/g'))"

# Before the eval, it turns into:
eval "array=("Joe" "Johnson" "25" "Red Blue")"
    
por 24.10.2016 / 04:17