Criando uma matriz com o IFS configurado para um valor diferente

5

Estou tentando construir um array e gravar em um arquivo nesse formato, ou seja, o conteúdo do arquivo deve ser algo como isto

hero_pairscore=( askdjfh sdf,sdlkfj lksf,dfgdf,dsflkgj,asdlkf ....)

Onde os elementos estão separados por comma . Eu escrevi o seguinte código para isso.

#!/bin/bash
#set -x

hero_pairscore=()
while read line
do

$( IFS=",";hero_pairscore+=( "$line" )
done < true_pairscore.txt

echo "hero_pairscore=( ${hero_pairscore[@]} )" > embed.txt

Mas o arquivo resultante contém apenas este hero_pairscore=( ) . O que há de errado com o meu código e como posso corrigi-lo para fornecer a saída desejada?

    
por Ashwin 21.04.2014 / 21:20

2 respostas

6

Tudo o que você precisa fazer é o seguinte:

  1. Defina a variável. Nós vamos usar isso:

    var="kijhg, fbjhku,,,ioy  fbjfr, kjmyhg"
    
  2. Defina o $IFS e evite a expansão do nome do arquivo:

    IFS=, ; set -f
    
  3. set shell $@ array para a saída.

    set -- $var
    
  4. Redefinir o shell pai $IFS e os parâmetros do shell:

    unset IFS ; set +f
    
  5. Hooray! Até preserva várias repetições e espaços e tudo!

    printf %s\n "$@"
    

    OUTPUT

    kijhg
     fbjhku
    
    
    ioy  fbjfr
     kjmyhg
    

De qualquer forma, aceite minha palavra. Todos os caracteres que não são , são preservados.

TRANSFORMAR

Eu recomendo especialmente usar o array de shell real em oposição ao array bash porque você pode transformar instantaneamente seu splitter.

printf %s "$*"

#OUTPUT#
kijhg  fbjhku   ioy  fbjfr  kjmyhg %

IFS=, ; printf %s "$*"

#OUTPUT#
kijhg, fbjhku,,,ioy  fbjfr, kjmyhg

Como $* tem a qualidade especial especificada pelo POSIX de dividir a matriz de argumentos do parâmetro posicional do shell no primeiro caractere de $IFS , é possível converter facilmente faixas de dados de maneira simples. Você pode "quote" -proteger a matriz de argumentos e ainda dividi-la em qualquer caractere único que desejar. Contanto que você acerte da primeira vez, isto é.

APPEND / PREPEND

POSIX também especifica qualidades especiais para "$@" . Além dos formulários de endereçamento "$1"... eval "\${$#}" para cada argumento, o parâmetro "$@" - quando citado - é expandido com segurança para todos os argumentos do shell, já que eram set , independentemente do valor atual de $IFS. Então, se você quiser adicione uma lista ao começo da sua matriz que você faz:

set -- $list "$@"

Para a cabeça / cauda:

set -- $head "$@" $tail

Para triplicar sua matriz:

set -- "$@" "$@" "$@"

TOTALMENTE AGORA

A menos que seu fluxo de dados seja muito grande, o seguinte pode ser um pouco mais rápido do que sua operação atual (embora, se você estiver trabalhando com arquivos, seria muito melhor evitar totalmente a divisão de shell) :

( set -f -- ; IFS=, ; while read -r line ; do set -- "$@" $line ; done
printf %s "$*" ) | cat >out

TALVEZ TR?

O que eu não entendo é isso - o que você está fazendo? Você está tentando substituir novas linhas por vírgulas? Quero dizer - os dados já estão separados por vírgulas, exceto apenas as novas linhas? Se assim for:

tr '\n' ',' <in >out
    
por 22.04.2014 / 00:08
5

Para fazer o que eu acho que você está tentando fazer, que é lido em cada campo separado por vírgula em true_pairscore.txt em uma variável de matriz, não há muito problema com seu código. O $( no início da linha IFS está obviamente errado e faria com que o script tivesse um erro (talvez essa seja a razão pela qual você não obtém nenhuma saída). Além disso, a principal correção para o seu código seria apenas remover as aspas em torno de $line , pois você deseja que bash faça a divisão de palavras em torno de IFS (geralmente é isso que você usa para evitar):

#!/bin/bash

set -o noglob
OIFS=$IFS
IFS=","
hero_pairscore=()

while IFS= read -r line
do
  hero_pairscore+=( $line )
done < true_pairscore.txt

echo "hero_pairscore=( ${hero_pairscore[@]} )" > embed.txt

set +o noglob
IFS=$OIFS

No entanto, aqui está um truque para fazer o acima em apenas duas linhas:

IFS=$',\n' read -ra hero_pairscore -d '' <true_pairscore.txt
echo "hero_pairscore=( ${hero_pairscore[@]} )" > embed.txt

Atualizar

Se o arquivo embed.txt tiver que ser originado em outro shell bash , você provavelmente desejará citar cada elemento da matriz hero_pairscore escrita. Para fazer isso, substitua o echo "hero_pairscore=( ${hero_pairscore[@]} )" por:

echo "hero_pairscore=( $(printf '"%s" ' "${hero_pairscore[@]}") )"
    
por 21.04.2014 / 23:01