Bash use variables as indexes to array - arrays

how to assign to a variable in Bash an array element such that the array is index itself by a variable (a most trivial thing in any language but seems special in bash?)
I tried many variants such as:
let temp1=list1[list1Index]
or
temp1=${list1[$list1Index]}
none of them work obviously. No error but nothing is displayed by echo $temp1
What can I do?
here is the full code (with dummy names for paths):
#! /bin/bash
pathFrontalGray='/mnt/c/Users/dummyName/'
list1=('x' 'y' 'z' 'a' 'b' 'c')
prefix1='dummyName'
echo $pathFrontalGray
touch fileNamesGray.txt
ls $pathFrontalGray > fileNamesGray.txt
fileGray='fileNamesGray.txt'
list1Index=0
i=0
while IFS= read -r line
do
let i=i+1
echo $i
#means if NOT divisibe by 9 -> if <expr evaluated to 0> -> equiv if false
if (($i % 9));then
let list1Index=list1Index+1
fi
temp1=$list1[$((list1Index))]
echo $temp1
#mv $pathFrontalGray$line $prefix1${list1[$list1Index]}
# display $line or do somthing with $line
#printf '%s\n' "$line"
done <"$fileGray"

I found the problem. I m sorry in fact
curr1=${list1[index1]}
works fine. The problem was that the echo of that got lost in lots of other stuff displayed. Sorry for the inconvenience. I guess I was a bit tired...

Related

storing user values in an array then comparing these variables using bash

while read line
do
if [ $line -ge $zero ]
then
a+=($line) ##here I am attempting to store the values in an array
else
for i in ${a[#]}
do
echo $(a[$i]) ## here I am trying to print them
done
fi
what is going wrong? it is giving this error:
a[1]: command not found
a[2]: command not found
a[3]: command not found
done
From the begining
if [ $line -ge $zero ]
what data type should be in $line?
-ge used in numeric comparison. If $line is a string than use = or if you just wnt to check that it's not empty use this syntax if [[ "$line" ]]
Next.
a+=($line)
Again if $line is a string then you should wrap in "" like this a+=("$line")
coz line can contain spaces.
For loop.
for i in ${a[#]}
do
echo $(a[$i]) ## here I am trying to print them
You'r messing with syntax here for i in ${a[#]} will iterate over arrays values, not indexes. And again if values are strings use "" like this for i in "${a[#]}"
So this echo $(a[$i]) won't work by 2 reasons. First you should use {} here, like this echo ${a[$i]}, second $i is not index, but it's may actualy work if it's a digit but in a wrong way. So here you need just echo $i coz $i is alredy a value from a array. Or rewrite foor loop.
for i in ${!a[#]}
do
echo ${a[$i]} ## here I am trying to print them
done
And last but not least, there is no done at the end of this script or it's just a part? So in the and it should look like this.
while read line; do
if [[ $line ]]; then
a+=( "$line" ) ##here I am attempting to store the values in an array
else
for i in ${!a[#]}; do
echo ${a[$i]} ## here I am trying to print them
done
fi
done < data.txt
echo ${a[#]} # print rusult

Bash While Loop Variable Mishaps

Before you get concerned, this (hopefully) isn't another of the many threads about having variable access problems from a while loop in BASH. I looked at those and implemented the redirect method, but I'm having some issues.
Code:
#!/bin/bash
rm /tmp/sched.now
rm /tmp/sched.later
NOWURL="schedNOWurl"
LATERURL="schedLATERurl"
curl -s $NOWURL --output /tmp/sched.now
curl -s $LATERURL --output /tmp/sched.later
re='^[0-9]+$'
if grep -q 'no shifts' /tmp/sched.now ; then
nowpeople[0]="No Shifts Assigned For This Time"
nowtime[0]="Now"
else
while read line
do
if [[ ${line:0:1} =~ $re ]] ; then
nowtime[$nowcount]=$line
((nowcount++))
elif [[ ${line:0:1} == '-' ]] ; then
nowpeople[$nowcount]=$line
((nowcount++))
fi
done < /tmp/sched.now
fi
declare -a latertime
declare -a laterpeople
if grep -q 'no shifts' /tmp/sched.later ; then
laterpeople[0]="No Shifts Assigned For This Time"
latertime[0]="Until 23:59"
else
while read line
do
if [[ ${line:0:1} =~ $re ]] ; then
latertime[$latercount]=$line
((latercount++))
elif [[ ${line:0:1} == '-' ]] ; then
laterpeople[$latercount]=$line
((latercount++))
fi
done < /tmp/sched.later
fi
echo ${nowpeople[#]}
echo ${nowtime[#]}
echo ${laterpeople[#]}
echo ${latertime[#]}
The URLs that I'm getting are HTML files. The text I'm attempting to pull in the loops looks something like this
11a-1:30p
- John Doe
with some HTML thrown above and below it. Note that these are all on their own lines.
The issue I'm facing is that the loops aren't saving all of the matches to the array. In the second loop, it should pull three entries into each array. Right now it pulls one with malformed text as follows:
- John Doe
1:30p-4pp
Notice the missing m in pm and the replaced m with a p in pp.
The strange thing is that if I echo $line before the array statement, the line is pulled from the file fine, so it sounds like it's something in the way I'm saving to the array.
Suggestions? Please let me know if you need more details.

bash array substitution broken on for loop

I have this piece of bash code in a script:
[..]
ARRAY=("foo-2" "foo-3" "foo-4")
IGNORE=2
while sleep 2
do
for ii in "${ARRAY[#]/foo-${IGNORE}/}"
do
echo $ii
done
[..]
done
This piece of code on its own works. But in my full script a weird thing happens:
First loop of sleep runs well. 2nd iteration however, uses the ${ARRAY[#]/foo-${IGNORE}/} as a literal string. Making a single echo command in the for loop.
Debugging the for loop:
Works:
for module in ${ARRAY[#]}
Also works:
for module in $(echo ${ARRAY[#]} | xargs -n 1 | grep -v foo-${IGNORE})
What do you think might be the problem? Is it some sort of bash limitation? Is there any other way you can suggest I do this?
Thanks!
"${ARRAY[#]/foo-${IGNORE}/}" should expand to multiple elements but one of them would just be an empty string and not completely ignored.
See this:
# A=(1 2 3)
# printf '|%s|\n' "${A[#]//1/}"
||
|2|
|3|
It also sounds like your array doesn't expand at all. Probably cause of it is that your shell is not being run by Bash.
Anyway better just compare your element instead:
for ii in "${ARRAY[#]}"
do
[[ $ii == "foo-$IGNORE" ]] && continue
echo $ii
done
You can also use globbing:
for ii in "${ARRAY[#]}"
do
[[ $ii == *"foo-$IGNORE"* ]] && continue
echo $ii
done

shell adding string to an array

I am having some trouble adding a string to an array within a loop. For some reason it always adds the same line. Here is my code:
declare -a properties
counter=0
while read line
do
if [[ ${line} == *=* ]]
then
properties[${counter}]=${line}
(( counter=counter + 1 ))
fi
done < ${FILE}
for x in ${!properties[#]}
do
echo "the value is $properties[x]"
done
For some reason each element in the array is the first line in the file. I must be doing something wrong, just not sure what.
Any help would be greatly appreciated
Try this script:
declare -a properties
while read line
do
[[ "${line}" == *=* ]] && properties+=("$line")
done < "${FILE}"
for x in "${properties[#]}"
do
echo "the value is "$x"
done
As #twalberg mentions in this comment, the problem is not in the top loop, but in the bottom one:
for x in ${!properties[#]}
do
echo "the value is $properties[x]"
done
Array references always need braces { ... } to expand properly.
For some reason each element in the array is the first line in the
file.
Not so. The array is correctly populated, but you need to change the reference to the array from:
echo "the value is $properties[x]"
to:
echo "the value is ${properties[x]}"
Just a simple oversight.
A much simpler way to add an element to an array is to simply use the syntax:
VARNAME+=("content")
Also, as written, your bug may be here:
(( counter=counter + 1 ))
It probably should be one of these three:
(( counter=$counter + 1 ))
counter+=1
counter=$[$counter+1]
counter=$(($counter + 1))
This KornShell (ksh) script worked fine for me. Let me know if anything.
readFileArrayExample.ksh
#! /usr/bin/ksh
file=input.txt
typeset -i counter=0
while read line
do
if [[ ${line} == *=* ]]; then
properties[${counter}]="${line}"
((counter = counter + 1))
echo "counter:${counter}"
fi
done < "${file}"
#echo ${properties[*]}
for x in "${properties[#]}"
do
echo "${x}"
done
readFileArrayExample.ksh Output:
#:/tmp #ksh readFileArrayExample.ksh
counter:1
counter:2
counter:3
a=b
a=1
b=1
#:/tmp #
input.txt
a-b
a+b
a=b
a=1
b=1
1-a

Array returns false when i know it should be true

I know that this particular volume should be coming out as true but it keeps returning as false. Can anyone see what is wrong with it? My guess is it has something to do with the if statement but i have no idea what. the "3D/Gather" are 2 seperate strings but i want it so that if they are together then it returns true. This is the start of what is going to be quite a long script so i want to make it a function that i can call upon later on. Thanks in advance for your help.
#!/bin/bash
session_path=$PWD/testSess/3DBPvol.proc
outPath=""
sess=$session_path
{
ThreeD="false"
while read line; do
IFS=" "
arr=$(echo ${line})
unset IFS
for i in ${arr[#]} ; do
if [[ "$i" =~ "3D" ]] && [[ "$i" =~ "Gather" ]]; then
ThreeD="true"
fi
done
done < "$sess"
echo "Is 3D? $ThreeD"
}
arr=$(echo ${line})
This doesn't create an array, you'd need extra parens:
arr=($(echo ${line}))
But you don't actually need the echo, this should be enough:
arr=(${line})
So you want to see if the file under /proc contains "3D Gather"? You can do that simply with a grep:
#!/bin/bash
session_path=$PWD/testSess/3DBPvol.proc
grep -q '3D Gather' "$session_path" && ThreeD=true || ThreeD=false
echo "Is 3D? $ThreeD"
It seems you don't need to break the line into a BASH array. Consider this rafactored script that does the same job but with a lot less code:
ThreeD="false"
while read line; do
[[ "$line" == *"3D Gather"* ]] && ThreeD="true" && break
done < "$sess"
echo "Is 3D? $ThreeD"

Resources