2

I am not able to save values in an array. Below is the file data:

123|23.23|2.34|3.45|2019-20-1

I want the second, third and fourth values in an array. The code should be generic so that in future I may choose 4 parameter instead of 3 or different combinations of fields.

array ={23.33 2.34 3.45 2019-20-1}

Partially working code:

declare -a alpha=()

alpha=($(awk '{n = split($0, t, "|")
for(i = 0; ++i <= n;) print t[i]}' <<<'$2|$3|$4'))
echo "$alpha[@]"

I am passing input as: '$2|$3|$4'

I want the output in an array like below

alpha={$2 $3 $4}

When I print echo "${alpha[@]}" all values should be printed

Output : $2 $3 $4

*Note : Output should be with space between two values so that i can using the values in my further code as looping to fetch another values

5
  • 3
    There are now a number of very recent questions that I believe are all from you, circulating around the same general topics, e.g. about getting arrays out of awk. Not once have you let us know what the overall purpose of your exercises are. It may be that you are even not needing awk at all. – Kusalananda Jan 4 '20 at 13:04
  • 2
    In this question, for example, why would you want to use awk? The elements of the array are there. You could even just do echo '$2 $3 $4'... Consider adding context to you questions describing wty you want to do this. – Kusalananda Jan 4 '20 at 13:26
  • @terdon do one thing can you able to create a code where i pass column position in this format '2|4|5' ... then from file 2nd position value | 3rd position value and 5th position value need to be stored in an array – gonofo4925janmail.org Jan 4 '20 at 15:37
  • @Kusalananda do one thing can you able to create a code where i pass column position in this format '2|4|5' ... then from file 2nd position value | 3rd position value and 5th position value need to be stored in an array – gonofo4925janmail.org Jan 4 '20 at 15:37
  • If you are just trying to get the columns out of a single line, then I would use cut rather than awk (or mapfile into an array and then pick out the wanted entries). If you have multiple lines of input data, then it's unclear what the end result should be. – Kusalananda Jan 4 '20 at 15:59
0

This shall work in your case

alpha=( $(awk -F'|'  '{ for(i=1;++i<=NF;) printf $i" "}' yourfile ) )

used NF (Number of field instead of hard coding field numbers).

2
  • my friend i need only particular field detail value in place of $2 $3 $5 into my array-then this above will not work – gonofo4925janmail.org Jan 4 '20 at 15:17
  • @gonofo4925janmail.org why? Just use the fields you need. It is possible to add only specific fields to the array but that just makes the code more complicated for no real benefit. – terdon Jan 4 '20 at 15:46
0
#!/bin/bash

# Read the data into the array fields from the
# file called "file". This assumes that the data
# is a single line with fields delimited by
# |-characters.
mapfile -d '|' -t fields <file

# The last entry in the fields array will quite
# likely have a trailing newline at the end of it.
# Remove that newline if it exists.
fields[-1]=${fields[-1]%$'\n'}

# These are the column numbers from the original
# data that we'd like to keep.
set -- 2 3 4

# Extract those columns from the fields array. Note
# that we have to decrement the numbers by one as
# arrays in bash are indexed from zero.
for column do
        array+=( "${fields[column-1]}" )
done

# Output the elements of the resulting array:
printf '%s\n' "${array[@]}"

# For outputting with spaces in-between the values
# rather than newlines:
printf '%s\n' "${array[*]}"

There's no reason to output the values of the array at the end if you are going to use them for other things. Saying that you want to output the values in a particular format (with spaces between them) implies that you are just going to parse them again with some other code. That would be totally unnecessary as you already have the values in an array.

To loop over the array of values:

for value in "${array[@]}"; do
    # Use "$value" here.
done

Or, using the original data array fields:

for column in 2 3 4; do
    value=${fields[column-1]}
    # Use "$value" here.
done
0

This is the approach i needed. Any other method to do that please suggest with all your simple logic i tried on my own to create script

I have two files

lets me tell you about first file :

file1.txt 

The first file contain only one single line data [only one record]

The data is :

1234|23.23|45.34|34.34|2019-23-19|12:00:90

The data from file1.txt - indicates like below 
value in position[2] = sum of SAL
value in position[3] = sum of COL
value in position[4] = sum of PER

Now lets talk about second file. Which is file2.txt

The second file contain below data

ID|SAL|COL|PER|TAG|GER
1"|"0.04"|"8.08"|"16.16"|"2.2"|D"
2"|"0.04"|"8.08"|"16.16"|"2.34"|"B"
3"|"0.04"|"8.08"|"16.16"|"2.34"|"A"

Note all need to be generic code and that to function so that i should work with any scenario.

file1.txt logic imolemented

myscriptfile1.sh file1.txt '2|3|4|5'

when i run this it will give me an output i am storing into an array1

array1={23.23 45.34 34.34}

file2.txt logic implemented

  myscriptfile2.sh file2.txt 'SAL|COL|PER'

for column SAL calculating sum and same followed for remaining two column COL PER

when i run this it will give me an output i am storing into an array2

array2={12.12 13.24 34.34}

Now final logic the output of array1 and array2 need to be compared index to index like below

value of array1[0] = array2[0]
value of array1[1] = array2[1]
value of array1[2] = array2[2]

if matches then [0]=[0] , [1]=[1] , [2]=[2] then should display SUCCESS or FAIL

SUCCESS when all values are matched according to respective indexed

FAIL when one of the value does not match

The approach should be like :

myscriptfile.sh file1.txt '2|3|4'

in future instead of '2 3 4 ' -> it might be 5 parameter '2|3|4|5|6' the code should be able to cut those data from file. The file will contain that many column record no need to worry

1234|23.23|45.34|34.34|23.4|34.111|2019-23-19|12:00:90

Same applied for file2.txt. how many parameters we are cutting in file1.txt that many column name "sum" need to be cut from file2.txt. In this case data may be different no need to worry

ID|SAL|COL|PER|TAG|DIL|MILL|
myscriptfile2.txt file2.txt 'SAL|COL|PER|TAG|DIL'

My entire code :

#!/bin/bash


FILE1="$1"

# position : example - '$2|$3|$4'
FILE1_POSITION="$2"

# Checking file exist or not 
if [ ! -f "$FILE1" ]
then
    echo "$0: File '$FILE1' not found."
else
    echo "$0: File '$FILE1' found."
fi


# Initialising the counter to zero
n=0

# # Cutting the FILE1_POSITION data separated with delimiter '|' and storing into array 
# Declaring th dynamic array
declare -a ABC=()

# Assigning the position to array
ABC=($(awk '{n = split($0, t, "|")
for(i = 0; ++i <= n;) print t[i]}' <<<$FILE1_POSITION))
echo "${ABC[@]}"

# Looping multiple position values in an array and storing values into counter 
for col in "${ABC[@]}"
do
      file1array[n]=`cut -d'|' -f$col $FILE1`
      ((n=n+1))
done 

############### FILE 2 [SUM of COLUMNS] #########################################################################


FILE2="$3"

# Column name for which sum required [format : 'SAL|COL|PER']
FILE2_COLUMN_NAME="$4"

# Checking file exist or not
if [ ! -f "$FILE2" ]
then
     echo "$0: File '$FILE2' not found."
     else
     echo "$0: File '$FILE2' found."
fi

# Getting position of column name and storing it into an array
FILE2_POSITION=( $(awk -F"|" 'NR==1{for(i=1;i<=NF;i++){if ($i ~ /'$FILE2_COLUMN_NAME'/){print i;}}}' $FILE2) )


# Initialising the counter to zero
m=0

# Looping multiple position values in an array and storing values into counter
for each in "${FILE2_POSITION[@]}"
do
   file2array[m]="$(awk -F'"?\\|"?' '{T+=$('$each')} END { printf "%.2f\n", T }' $FILE2)"
   ((m=m+1))
done



#printing number of values in array
echo "COUNT OF BALANCE COLUMN FOUND"
echo "${#file1array[@]}"

file1count=${#file1array[@]}
echo $file1count


# printing all values in array
echo "PRINTING ALL BALANCE COLUMN DATA"
echo "${file1array[@]}"



#printing number of values in array 
echo "COUNT OF COLUMN SUM FOUND"
echo "${#file2array[@]}"
file2count=${#file2array[@]}
echo $file2count


# printing all values in array
echo "PRINTING ALL SUM OF COLUMN"
echo "${file2array[@]}"


########################### CHECKING ARRAY TO ARRAY INDEX #####################################################################

# # comparing count of array 
if [ $file1count -eq $file2count ]
then 
   echo "Count matches = $file1count:$file2count"
else
   echo "Count Does not matches = $file1count:$file2count"
fi   

# # comapring array values by taking it as string 
if [[ "${file1array[*]}" == "${file2array[*]}" ]]; then
     echo SUCCESS
else
     echo FAIL
fi
###############################################################################################################################
0
0

The bash read command can store the fields into an array:

while IFS='|' read -r -a fields; do
    # do stuff with the elements of "${fields[@]}"
done < file
0

Splitting in bash is what happens when you don't quote a parameter expansion or command substitution, or $(<...) or arithmetic expansion.

So here:

IFS='|'                # split on | instead of the default of SPC|TAB|NL

set -o noglob          # disable globbing which is another side effect of leaving
                       # expansions unquoted

set -- $(<file.data)'' # do the splitting. The extra '' is so that
                       # a|b| is split into "a", "b" and "" for instance.
                       # also note that it splits an empty string into one empty
                       # element.

array=("$2" "$3" "$4")
-1

If you want to pass |-saparated data and store that in a bash array, you can do:

#!/bin/env bash

alpha=( $(sed 's/|/ /g' <<<"$@") )
## Arrays start counting at 0, so 1 is the 2nd value
for i in 1 2 3; do
  echo "Field $((i+1)) $i is: ${alpha[i]}"
done

You can then run the script like this:

$ foo.sh "123|23.23|2.34|3.45|2019-20-1"
Field 2 1 is: 23.23
Field 3 2 is: 2.34
Field 4 3 is: 3.45

If you only want the specific values stored, for some reason, you can do something like:

#!/bin/env bash

temp=( $(sed 's/|/ /g' <<<"$@") )
alpha=( ${temp[1]} ${temp[2]} ${temp[3]} )
echo "Fields 2, 3 and 4 were: ${alpha[@]}"

Which would print:

$ foo.sh "123|23.23|2.34|3.45|2019-20-1"
Fields 2, 3 and 4 were: 23.23 2.34 3.45
1
  • the above code is not a generic code ... means should work with any scenario in future it might be like that the value in $10 position $23 position need to be stored in an array how will it a effective code the parameters should be passed like this with script : script.sh filename '10|23' incase in their is a requirement like instead of 10 and 23 one more value needed then it should be like this '10|23|45|23' it should take and cut the values for that store in an array – gonofo4925janmail.org Jan 5 '20 at 7:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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