I have a file that contains multiple words with commas. I want to read a file and store these words into array. In this file, first line is header, the other lines are datum. But some datum are null.So, this null characters need to be 0 For instance;
H1;H2;H3;H4
12;23;33;44
44;;7;8
13;;;9
So I want to skip first line and put datum into 4 array=>
H1 array= 12;44;13
H2 array= 23;0;0
H3 array= 33;7;0
H4 array= 44;8;9
So my code is like that:
array=()
awk 'NR>1' $filename2 | while read line
do
cntr=0
IFS=";"
for i in $line; do
if [ -z $i ]; then array[cntr]=0;
else array[cntr]=$i;
fi
cntr=$[$cntr +1]
done
h1array+=("${array[0]}")
h2array+=("${array[1]}")
h3array+=("${array[2]}")
h4array+=("${array[3]}")
done
for ((i=0;i<3;i++)); do
echo "${h1array[$i]}"
done
for ((i=0;i<3;i++)); do
echo "${h2array[$i]}"
done
for ((i=0;i<3;i++)); do
echo "${h3array[$i]}"
done
for ((i=0;i<3;i++)); do
echo "${h4array[$i]}"
done
So,it prints null in terminal. How can I do this? Thank you
Is this what you are after?
#!/bin/bash
while read -r line; do
[[ "${line}" == *';'* ]] || continue
IFS=';' read -r h1 h2 h3 h4 <<< "${line}"
h1array+=("${h1:-0}")
h2array+=("${h2:-0}")
h3array+=("${h3:-0}")
h4array+=("${h4:-0}")
done < <(tail -n +2 input.txt)
echo "h1array = ${h1array[#]}"
echo "h2array = ${h2array[#]}"
echo "h3array = ${h3array[#]}"
echo "h4array = ${h4array[#]}"
.
$ ./t.sh
h1array = 12 44 13
h2array = 23 0 0
h3array = 33 7 0
h4array = 44 8 9
Related
In bash, I would like to loop over a previously defined array, which contains filenames. In turn, each file of the array must be readed and processed dynamically (while read line...).
This is an example of what the files of the array contains:
_VALUE1_,_VALUE1_,1,Name 1
_VALUE2_,_VALUE2_,1,Name 2
_VALUE3_,_VALUE3_,1,Name 3
_VALUE4_,_VALUE4_,1,Name 4
_VALUE5_,_VALUE5_,1,Name 5
This is what I've tested with no luck.
#!/bin/bash
. functions.sh
GEN_ARQ_ARRAY=("./cfg_file.txt" "./euro_file.txt" "./zl_file.txt")
WB_ARQ_ARRAY=("./rn_cfg_wb_file.txt" "./rn_eur_wb_file.txt" "./rn_zl_wb_file.txt")
BN_ARQ_ARRAY=("./rn_cfg_bn_file.txt" "./rn_eur_bn_file.txt" "./rn_zl_bn_file.txt")
AM_ARQ_ARRAY=("./rn_cfg_am_file.txt" "./rn_eur_am_file.txt" "./rn_zl_am_file.txt")
STATUS_BOOL=true
for i in "${!GEN_ARQ_ARRAY[#]}"; do
while IFS=$'\r' read -r line || [[ -n "$line" ]];do
STACK_NAME=${line%%,*} # Gets the first substring of a string divided by ','
STACK_STATUS=$(curl -su "${USERNAME}":"${PASSWORD}" -X GET http://"${SERVER_NAME}":9100/api/stacks/"${STACK_NAME}"/state | ./jq-linux64 -cr '.result.value')
if [[ $(echo "$STACK_STATUS" | tr -d '\r') == "$STATUS_BOOL" ]]; then
echo "${line}" >> "${GEN_ARQ_ARRAY[i]}"
case ${line} in
*"ARQBS"*|*"ARCBS"*|*"ARQWB"*|*"ARCWB"*) echo "${line}" >> "${WB_ARQ_ARRAY[$i]}";;
*"ARQOF"*|*"ARCOF"*|*"ARQBN"*|*"ARCBN"*) echo "${line}" >> "${BN_ARQ_ARRAY[$i]}";;
*"ARQAM"*|*"ARCAM"*) echo "${line}" >> "${AM_ARQ_ARRAY[$i]}";;
*) echo "$(logWarn) No matches -- ${STACK_NAME}" | tee -a "$LOGFILE";;
esac
else
echo "$(logInfo) ${STACK_NAME} is not running" | tee -a "$LOGFILE"
fi
done < "${GEN_ARQ_ARRAY[i]}"
done
Problem here is that the for loop starts, detects array content, gets the first value of the array, enter into while, and it constantly loops in the first position of the array even with the end of the file is reached. I can't find the way to exit the while loop and continue with the next array position.
I'm pretty sure there is a better way to implement this.
Hearing your ideas!
Edit:
Solved by replacing the line echo "${line}" >> "${GEN_ARQ_ARRAY[i]}", which was in-loop filling up the file.
Solved by replacing the line echo "${line}" >> "${GEN_ARQ_ARRAY[i]}", which was in-loop filling up the file. Once I did, the code worked flawlessly.
I need to split 2 numbers in the form(they are from a text file):
Num1:Num2
Num3:Num4
And store num1 into array X and number 2 in array Y num 3 in array X and num4 in array Y.
With bash:
mapfile -t X < <(cut -d : -f 1 file) # read only first column
mapfile -t Y < <(cut -d : -f 2 file) # read only second column
declare -p X Y
Output:
declare -a X='([0]="num1" [1]="num3")'
declare -a Y='([0]="num2" [1]="num4")'
Disadvantage: The file is read twice.
You could perform the following steps:
Create destination arrays empty
Read file line by line, with a classic while read ... < file loop
Split each line on :, again using read
Append values to arrays
For example:
arr_x=()
arr_y=()
while IFS= read line || [ -n "$line" ]; do
IFS=: read x y <<< "$line"
arr_x+=("$x")
arr_y+=("$y")
done < data.txt
echo "content of arr_x:"
for v in "${arr_x[#]}"; do
echo "$v"
done
echo "content of arr_y:"
for v in "${arr_y[#]}"; do
echo "$v"
done
Here is a quick bash solution:
c=0
while IFS=: read a b ;do
x[$c]="$a"
y[$c]="$b"
c=$((c+1))
done < input.txt
We send the input.txt to a while loop, using Input Field Separator : and read the first number of each line as $a and second number as $b. Then we add them to the array as you specified. We use a counter $c to iterate the location in the arrays.
Using =~ operator to store the pair of numbers to array $BASH_REMATCH:
$ cat file
123:456
789:012
$ while read -r line
do
[[ $line =~ ([^:]*):(.*) ]] && echo ${BASH_REMATCH[1]} ${BASH_REMATCH[2]}
# do something else with numbers as they will be replaced on the next iteration
done < file
I have a file like this below:
-bash-4.2$ cat a1.txt
0 10.95.187.87 5444 up 0.333333 primary 0 false 0
1 10.95.187.88 5444 up 0.333333 standby 1 true 0
2 10.95.187.89 5444 up 0.333333 standby 0 false 0
I want to fetch the data from the above file into a 2D array.
Can you please help me with a suitable way to put into an array.
Also post putting we need put a condition to check whether the value in the 4th column is UP or DOWN. If it's UP then OK, if its down then below command needs to be executed.
-bash-4.2$ pcp_attach_node -w -U pcpuser -h localhost -p 9898 0
(The value at the end is getting fetched from the 1st column.
You could try something like that:
while read -r line; do
declare -a array=( $line ) # use IFS
echo "${array[0]}"
echo "${array[1]}" # and so on
if [[ "$array[3]" ]]; then
echo execute command...
fi
done < a1.txt
Or:
while read -r -a array; do
if [[ "$array[3]" ]]; then
echo execute command...
fi
done < a1.txt
This works only if field are space separated (any kind of space).
You could probably mix that with regexp if you need more precise control of the format.
Firstly, I don't think you can have 2D arrays in bash. But you can however store lines into a 1-D array.
Here is a script ,parse1a.sh, to demonstrate emulation of 2D arrays for the type of data you included:
#!/bin/bash
function get_element () {
line=${ARRAY[$1]}
echo $line | awk "{print \$$(($2+1))}" #+1 since awk is one-based
}
function set_element () {
line=${ARRAY[$1]}
declare -a SUBARRAY=($line)
SUBARRAY[$(($2))]=$3
ARRAY[$1]="${SUBARRAY[#]}"
}
ARRAY=()
while IFS='' read -r line || [[ -n "$line" ]]; do
#echo $line
ARRAY+=("$line")
done < "$1"
echo "Full array contents printout:"
printf "%s\n" "${ARRAY[#]}" # Full array contents printout.
for line in "${ARRAY[#]}"; do
#echo $line
if [ "$(echo $line | awk '{print $4}')" == "down" ]; then
echo "Replace this with what to do for down"
else
echo "...and any action for up - if required"
fi
done
echo "Element access of [2,3]:"
echo "get_element 2 3 : "
get_element 2 3
echo "set_element 2 3 left: "
set_element 2 3 left
echo "get_element 2 3 : "
get_element 2 3
echo "Full array contents printout:"
printf "%s\n" "${ARRAY[#]}" # Full array contents printout.
It can be executed by:
./parsea1 a1.txt
Hope this is close to what you are looking for. Note that this code will loose all indenting spaces during manipulation, but a formatted update of the lines could solve that.
I am trying to store the contents of a .txt file in two sets of arrays in bash. The file is a list of characteristics for given data files, delimited by vertical bars (|). So far, I have written code that reads the file and prints each line of data separately, each followed by the given sections of the line.
#prints line of text and then separated version
while IFS='' read -r line || [[ -n "$line" ]]
do
echo "Text read from file: $line"
words=$(echo $line | tr "|" "\n")
for tests in $words
do
echo "> $tests"
done
done < "$1"
Example output:
Text read from file: this|is|data|in|a|file
> this
> is
> data
> in
> a
> file
Text read from file: another|example|of|data
> another
> example
> of
> data
Is there a way for me to store each individual line of data in one array, and then the broken up parts of it within another? I was thinking this might be possible using a loop, but I am confused by arrays using bash (newbie).
OK -- I just read in the lines like you have done, and append them to the lines array. Then, use tr as you have done, and append to the words array. Just use the parentheses to mark them as array elements in the assignments:
$ cat data.txt
this|is|data|in|a|file
another|example|of|data
$ cat read_data.sh
#!/bin/bash
declare -a lines
declare -a words
while IFS='' read -r line || [[ -n "$line" ]]
do
echo "Text read from file: $line"
lines+=( $line )
words+=( $(echo $line | tr "|" " ") )
done < "$1"
for (( ii=0; ii<${#lines[#]}; ii++ )); do
echo "Line $ii ${lines[ii]}"
done
for (( ii=0; ii<${#words[#]}; ii++ )); do
echo "Word $ii ${words[ii]}"
done
$ $ ./read_data.sh data.txt
Text read from file: this|is|data|in|a|file
Text read from file: another|example|of|data
Line 0 this|is|data|in|a|file
Line 1 another|example|of|data
Word 0 this
Word 1 is
Word 2 data
Word 3 in
Word 4 a
Word 5 file
Word 6 another
Word 7 example
Word 8 of
Word 9 data
I have a flat file which contains the following
INDIA USA SA NZ AUS ARG GER BRA
so there are eight columns altogether . Now I want to store the indexes of those columns only which starts with A into an array.
For that I tried the following statement
awk '{for(i=1;i<=NF;i++){if($i~/^A/){set -A newArray $i}}}' testUnix.txt
when I echo the file using
echo "${newArray[*]}"
it's printing 5 6 but whenever I am trying to get the length of that array
echo ${#newArray[#]}
its length is being shown as 1 only. Should not it be 2 ?
I also tried
awk '{y = 0;for(i=1;i<=NF;i++){if($i~/^A/){newArray[y] = $i ; y++}}}' testUnix.txt
but also it's producing the same result.
What am I missing ?Please explain. I intend to get the desired output 2.
No need for awk. You can loop through the elements and check if they start with A:
r="INDIA USA SA NZ AUS ARG GER BRA"
arr=()
for w in $r
do
[[ $w == A* ]] && arr+=("$w")
done
If you execute it then the arr array contains:
$ for i in "${arr[#]}"; do echo "$i"; done
AUS
ARG
And to confirm that is has two elements, let's count them:
$ echo "${#arr[#]}"
2
What is happening with your aproach?
awk '{for(i=1;i<=NF;i++){if($i~/^A/){set -A newArray $i}}}' testUnix.txt
this says set -A newArray but it is not really defining the variable in bash, because you are in awk.
What I would do to have a bash array :
bash_arr=( $(awk '{for(i=1;i<=NF;i++){if($i~/^A/){print $i}}}' file) )
echo "${bash_arr[#]}"
AUS ARG
And you don't even need awk in reality, bash is capable of doing regex :
for word in $(<file); do [[ $word =~ ^A ]] && basharr+=( "$word" ); done