Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am trying to construct an array and write to a file in this format, i.e. the file's content should be something like this

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

Where the elements are separated by comma. I wrote the following code for this.

#!/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

But the resultant file contains only this hero_pairscore=( ). What is wrong with my code and how can I correct it to give the desired output?

share|improve this question
    
Does the true_pairscore.txt file contain the "hero_pairscore=(" text?? –  glenn jackman Apr 21 at 20:38
add comment

2 Answers 2

To do what I think you are trying to do, which is read every comma separated field in true_pairscore.txt into an array variable there is not much wrong with your code. The $( at the start of the IFS line is obviously wrong and would cause the script to have an error (maybe this is the reason you get no output). Other than that, the main fix for your code would be just to remove the quotes around $line since you want bash to do word splitting around IFS (usually this is what you use them to avoid):

#!/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

However, here is a trick to do the above in only two lines:

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

Update

If the embed.txt file is to be sourced in another bash shell, you probably want to quote each element of the written hero_pairscore array. To do this, replace the echo "hero_pairscore=( ${hero_pairscore[@]} )" with:

echo "hero_pairscore=( $(printf '"%s" ' "${hero_pairscore[@]}") )"
share|improve this answer
add comment

All you need to do here is this:

  1. Set the variable. We'll use this:

    var="kijhg, fbjhku,,,ioy  fbjfr, kjmyhg"
    
  2. Set the $IFS and prevent filename expansion:

    IFS=, ; set -f
    
  3. set shell $@array to output.

    set -- $var
    
  4. Reset parent shell $IFS and shell params:

    unset IFS ; set +f
    
  5. Hooray! It even preserves multiple repeats and spaces and all!

    printf %s\\n "$@"
    

    OUTPUT

    kijhg
     fbjhku
    
    
    ioy  fbjfr
     kjmyhg
    

Anyway, take my word for it. Every character that is not a , is preserved.

TRANSFORM

I especially recommend using the real shell array as opposed to the bash array because you can instantly transform its splitter.

printf %s "$*"

#OUTPUT#
kijhg  fbjhku   ioy  fbjfr  kjmyhg %

IFS=, ; printf %s "$*"

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

Because $* has the special POSIX-specified quality of splitting the shell's positional parameter argument array on the first character of $IFS you can easily convert swathes of data as simply as that. You can "quote"-protect the argument array and still split it on any single character you like. As long as you get it right the first time, that is.

APPEND/PREPEND

POSIX also specifies special qualities to "$@". Aside from the "$1"... eval "\${$#}" addressing forms for each argument, the "$@" parameter - when quoted - safely expands to all of the shell's arguments as they were last set regardless of the current value of $IFS. So if you want to add a list to the beginning of your array you do:

set -- $list "$@"

To the head/tail:

set -- $head "$@" $tail

To triple your array:

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

ALTOGETHER NOW

Unless your datastream is very large, the following might be a little quicker than your current operation (though, if you're working with files, you'd be far better off to eschew shell splitting altogether):

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

MAYBE TR?

What I don't understand though is this - just what are you doing? Are you trying to replace newlines with commas? I mean - is the data already comma separated excepting only newlines? If so:

tr '\n' ',' <in >out
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.