I am trying to substitute variable value inside array so as to update array values based on command line inputs.
e.g. I am receiving IP address as command line argument for my TCL script and trying to update commands with recvd IP value.
My array is:
array set myArr { 1 myCmd1("192.268.2.1","abc.txt")
2 myCmd2("192.268.2.1","xyz.txt")
3 myCmd3("192.268.2.1","klm.txt")
}
Here, "192.268.2.1" will actually be supplied as command line argument.
I tried doing
array set myArr { 1 myCmd1($myIP,"abc.txt")
2 myCmd2($myIP,"xyz.txt")
3 myCmd3($myIP,"klm.txt")
}
and other combinations like ${myIP}, {[set $myIP]} but none is working.
Thanks in advance for any help/inputs.
Use the list command
% set myIP 0.0.0.0
0.0.0.0
% array set myArr [list 1 myCmd1($myIP,"abc.txt") 2 myCmd2($myIP,"xyz.txt") 3 myCmd3($myIP,"klm.txt")]
% puts $myArr(1)
myCmd1(0.0.0.0,"abc.txt")
% puts $myArr(3)
myCmd3(0.0.0.0,"klm.txt")
%
I think your code will be easier to understand and easier to maintain if you don't try to use array set in this instance. You can get away with it if you are careful (see answers related to using list) but there's really no reason to do it that way when a more readable solution exists.
Here's my solution:
set myArr(1) "myCmd1($myIP,\"abc.txt\")"
set myArr(2) "myCmd2($myIP,\"xyz.txt\")"
set myArr(3) "myCmd3($myIP,\"klm.txt\")"
try:
array set myArr [list myCmd1($myIP, "abc.txt") 2 myCmd2($myIP, "xyz.txt") ... ]
Why? Because when you write {$var} in Tcl, it means $var and not the contents of the variable var. If you use list to create the list instead of the braces, variables are still evaluated.
Related
I have stored some strings in array1, lets say
array1[0]=apple
array2[1]=orange
and array2 contains
array2[0]=apple
array2[1]=mango
I want to loop through each element and check if they match. I tried using this condition inside loop but it didnot work
if [ "$array[i]" = "$array2[j]" ]
To access the elements of an array in bash you have to use ${array[i]} instead of just $array[i]. Because the [ cannot normally be part of a variable name, bash interprets $array[i] as ${array} followed by a literal [i].
By the way: https://www.shellcheck.net/ would have found this error.
This question already has answers here:
What is indirect expansion? What does ${!var*} mean?
(6 answers)
Closed 5 years ago.
I'm trying to take elements from $Table_Header_Labels in a loop and have it grab the string of the same name to be used for string length. Ex: Grabbed "Apple" from the array and then convert it to grab $Apple to get the string to do ${#Apple}.
#!/bin/bash
# Create Array
declare -a Array=('Red' 'Blue' 'White');
# Set Variable
Red="Apples are Red!"
# Get Size of Variable from Array Element
for i in ${Array[0]}
do
Element=${i}
Element_Size="${i}_Size"
# Print the generated one
echo "$Element_Size = ${#Element}"
# Print correct one to compare
echo "Red_Size = ${#Red}"
echo ""
done
Please take note I purposely made it so the loop only goes once. Currently, the Red_Size counts the array element itself which is three. I'm trying to get it to take the array element and grab the string assigned to the variable that is replicated by the array element.
Basic break down explanation: Apple => $Apple
Is this even possible with BASH?
To get the value of a variable whose name is in a variable,
you can use the ${!name} syntax.
For example, if i contains the name of a variable, "Red",
to get the value of the variable Red,
you can write ${!i}.
In your script:
Element=${!i} # if $i is "Red" -> $Red -> "Apples are Red!"
how to pass 2d array to function in shell script ?
i need to pass matrix to function but it do not work
tr(){
matrix="$3"
num_rows="$1"
num_columns="$2"
f1="%$((${#num_rows}+1))s"
f2=" %9s"
for ((i=1;i<=num_rows;i++)) do
for ((j=1;j<=num_columns;j++)) do
echo -ne "${matrix[$i,$j]}\t"
done
echo -e "\n"
done
tr $rows $columns $x
Use an associative array:
declare -A matrix
Then things like matrix[6,7]=42 will work because "6,7" ist just a string, and associative arrays accept strings as indices. You might as well write things like
matrix[one,two]=three
matrix[yet,another,dimension]="Perry Rhodan"
You can just write any string between [ and ]. Here is a complete example for how to use it.
#!/bin/bash
#
# Example for a function that accepts the name of an associative array ...
# ... and does some work on the array entries, e.g. compute their sum
# We assume that all *values* of the array are integers - no error check
sum() {
local s=0 # we don't want to interfere with any other s
declare -n local var="$1" # now var references the variable named in $1
for value in "${var[#]}" # value runs through all values of the array
do
let s+="$value"
done
echo sum is $s
}
declare -A m # now m is an associative array, accepting any kind of index
m[0,0]=4 # this looks like 2-dimensional indexing, but is is not
m[2,3]=5 # m will accept any reasonable string as an array index
m[678]=6 # m does not care about the number of commas between numbers
m[foo]=7 # m does not even care about the indices being numbers at all
sum m
As you see, the matrix m not really has 2 dimensions. It just takes any string as an index, as long as it does not contains certain shell syntax characters, and comma is allowed in the string.
Please note the reference declare -n ... - this allows simple access to the matrix from within the function and, most important, without knowing the name of the matrix. Thus you can call that function for several matrices with different names.
The keyword local is important. It means that, upon return, var is unset automatically. Otherwise you will have a reference "var" to an associative array. If you ever want to use var later, it will be hard to use it because you cannot use it as anything else but an associative array. And if you try to get rid of it by "unset var", bash will kindly remember that var refers to m, and delete your matrix m instead. In general, make variables in functions be local wherever possible. It even allows me to re-use a name. For example, using "s" as a variable name inside a function may appear dangerous because it might change the value of a global variable "s". But it doesn't - by declaring it local, the function has its own private variable s, and any s that might already exist is untouched.
Just as a demonstration: If you want to see the array indices in the loop, do this:
sum() {
local s=0 # we don't want to interfere with any other s
declare -n local var="$1" # now var references the variable named in $1
for i in "${!var[#]}" # !var means that we run through all indices
do # we really need a reference here because ...
let s+=${var["$i"]} # ... indirections like ${!$1[$i]} won't work
done
echo sum is $s
}
I am intending to change a global variable inside a function in BASH, however I don't get a clue about how to do it. This is my code:
CANDIDATES[5]="1 2 3 4 5 6"
random_mutate()
{
a=$1 #assign name of input variable to "a"
insides=${!a} #See input variable value
RNDM_PARAM=`echo $[ 1 + $[ RANDOM % 5 ]]` #change random position in input variable
NEW_PAR=99 #value to substitute
ARR=($insides) #Convert string to array
ARR[$RNDM_PARAM]=$NEW_PAR #Change the random position
NEW_GUY=$( IFS=$' '; echo "${ARR[*]}" ) #Convert array once more to string
echo "$NEW_GUY"
### NOW, How to assign NEW_GUY TO CANDIDATES[5]?
}
random_mutate CANDIDATES[5]
I would like to be able to assign NEW_GUY to the variable referenced by $1 or to another variable that would be pointed by $2 (not incuded in the code). I don't want to do the direct assignation in the code as I intend to use the function for multiple possible inputs (in fact, the assignation NEW_PAR=99 is quite more complicated in my original code as it implies the selection of a number depending the position in a range of random values using an R function, but for the sake of simplicity I included it this way).
Hopefully this is clear enough. Please let me know if you need further information.
Thank you,
Libertad
You can use eval:
eval "$a=\$NEW_GUY"
Be careful and only use it if the value of $a is safe (imagine what happens if $a is set to rm -rf / ; a).
In my script I want to return the string that does not match .
I tried puts $expect_out(buffer) but it did not work and gave me below error
can't read "expect_out(buffer)": no such variable
while executing
"puts "out is $expect_out(buffer)" "
code
expect {
-nocase -re "$arg3" { exit 0 }
timeout { puts "Does not matched, output is $expect_out(buffer)" ; exit 2 }"
}
The expect_out array doesn't exist until a match occurs, so if you haven't matched an expect call in your code previously and you actually reach your timeout clause, you receive the no such variable error.
Expect manpage
"Upon matching a pattern (or eof or full_buffer), any matching and previously unmatched output is saved in the variable expect_out(buffer). Up to 9 regexp substring matches are saved in the variables expect_out(1,string) through expect_out(9,string). If the -indices flag is used before a pattern, the starting and ending indices (in a form suitable for lrange) of the 10 strings are stored in the variables expect_out(X,start) and expect_out(X,end) where X is a digit, corresponds to the substring position in the buffer. 0 refers to strings which matched the entire pattern and is generated for glob patterns as well as regexp patterns."
You can test this via info exists expect_out and printing out the array keys/values (if it exists) using array names expect_out.
You can set the values explicity yourself via set expect_out(key) value, but there's no way (that I know of) to retrieve the non-matching string initially, bar using log_file expectoutput.txt and reading it back in if you timeout.