take value of argument into array as an index number - bash

argument_number=$#
for ((i = 2; i <= $argument_number; i++))
do
echo ${lower[$i]]}
done
I want to take argument value into array as index number for example if my second argumnet is 15 want to achive lower[15] but it gives lower[2] how can I do ,is there any suggestion,help

If I understand you correctly, the indices into array ${lower[#]} are given by command-line arguments; in this case, you can simply use:
shift # skip the 1st argument
for index; do # this loops over all command-line arguments; same as: for index in "$#"; do
echo "${lower[index]}"
done
Note:
I've double-quoted ${lower[index]} so as to protect the value from unwanted interpretation by the shell - unless you specifically want the shell to perform word-splitting and globbing on a variable value, you should double-quote all your variable references.
Array subscripts in Bash are evaluated in arithmetic context, which is why variable index can be referenced without the usual $ prefix.

Related

What does the # symbol mean in this bash for loop? [duplicate]

I know that one can get the length of an array in bash by doing ${#arrayname[#]}.
My question is: is this just something that I have to memorize, or can this syntax be broken down into understandable parts? For instance, what does the # symbol mean where one would expect to find the index? Why the #?
# at the beginning of a variable reference means to get the length of the variable's value. For a normal variable this means its length in characters. # is the "number" sign, so you can remember this as meaning "the number of things in the variable".
# or * in an array index means to use the whole array, not a specific element, and instead of returning the number of characters, it returns the number of array elements. * is used as a wildcard in many contexts, so this should be easy to remember. Also, $* and $# are used to mean all the arguments to a shell script, so the parallel with all the array elements should be obvious.
You can't just write ${#arrayname} because when you use an array variable without a subscript, it's equivalent to element 0 of the array. So ${#arrayname} is the same as ${#arrayname[0]}, which is the number of characters in the first element of the array.
You should memorize. :) The # usually means number. e.g. the
$# - is the number of arguments
${#str} - length of the string $str
${#arr[#]}" - length (number of elements) of the array arr
${#arr} - the length of the 1st element of the array (like the str above)
Unfortunately the ${parameter#word} or ${parameter##word} has nothing with numbers. (it removes the shortest/longest word from the beginning of the parameter.
And also, the # .... is comment ;)
In general usage of form ${#PARAMETER} returns the length in number of characters and NOT bytes of the parameter's value.
myString="Hello StackOverflow!"
printf "%s\n" "${#myString}"
20
But for arrays, this expansion type has two meanings:
For individual elements, it reports the string length of the element
(as for every "normal" parameter)
For the mass subscripts # and * it
reports the number of set elements in the array
Consider an example over arrays,
myArray=(1 2 3 4 15)
printf "%s\n" "${myArray[#]}" # <-- Gives me list of elements
1
2
3
4
15
printf "%s\n" "${#myArray[#]}" # <-- Gives me number of elements
5
It gets interesting now, the length of the last element 2 can be obtained by doing
printf "%s\n" "${#myArray[4]}"
2
The '#' acts the same way as '*'. Instead of providing a specific index this references the full thing.
The '#' is telling bash you want the length
https://www.cyberciti.biz/faq/finding-bash-shell-array-length-elements/

Combine a variable and string and get the value of the variable formed in a single line

I was writing a script where I came across a situation.
Audio_Repo = "/src/audio_123";
Audio_ImgTag = "aud021882";
Audio_Enable = 1;
.....
Video_Repo = "/src/vid_823";
Video_ImgTag = "video9282";
Video_Enable = 0;
....
#Say proj_var ="Audio"
#it could be either Audio or Video based on some conditional check
....
proj_var = "Audio"
....
PROJECT_REPO= ${!{$proj_var"_Repo"}}
#PROJECT_REPO should hold the value "src/audio_123"
But the above representation throws bad substitution error
I know that I could use a temporary variable as follows
temp= $proj_var"_Repo";
PROJECT_REPO = ${!temp};
But I have many properties and I do not want to use temporary variables for each of them. Instead I want single line substitutions.
One way to do it is to use eval:
#! /bin/bash -p
Audio_Repo="/src/audio_123"
Audio_ImgTag=aud021882
Audio_Enable=1
# ...
Video_Repo=/src/vid_823
Video_ImgTag=video9282
Video_Enable=0
# ....
# Say proj_var="Audio"
# it could be either Audio or Video based on some conditional check
# ....
proj_var="Audio"
# ....
eval "Project_Repo=\${${proj_var}_Repo}"
# Project_Repo should hold the value "src/audio_123"
printf '%s\n' "$Project_Repo"
The code prints /src/audio_123.
eval is dangerous, and should be avoided if possible. See Why should eval be avoided in Bash, and what should I use instead?. In this case the temporary variable, despite the increased verbosity, is a better option.
I replaced PROJECT_REPO with Project_Repo to avoid possible a possible clash with an environment variable. See Correct Bash and shell script variable capitalization.
I've fixed some Bash syntax issues in the code in the question. Spaces around = are errors. Semicolons at the ends of lines are unnecessary.
Shellcheck issues some warnings for the code, but they are all harmless.
Another option is to use a helper function:
# ...
# Set the value of the variable whose name is in the first parameter ($1)
# to the value of the variable whose name is in the second parameter ($2).
function setn { printf -v "$1" '%s' "${!2}" ; }
# ...
setn Project_Repo "${proj_var}_Repo"
Using the setn (a poor name, choose a better one) function avoids both a temporary variable and eval.
Uses arrays, not variable names you need to manipulate.
Repo=0
ImgTag=1
Enable=2
Audio=(/src/audio_123 aud021882 1)
Video=(/src/vid_823 video9282 0)
proj_repo=Audio[$Repo]
project_var=${!proj_repo}

What does "${var:x:y}" mean in Bash?

Inside the function of a shell script I see something like this
func() {
local x
x=${1:3:1}
...
}
What does x=${1:3:1} mean? I know that $1, $2 and $3 are arguments of the function. So does the above statement mean that x = $1:$2:$3?
This is called parameter expansion in shell.
${PARAMETER:OFFSET:LENGTH}
This one can expand only a part of a parameter's value, given a position to start and maybe a length. If LENGTH is omitted, the parameter will be expanded up to the end of the string. If LENGTH is negative, it's taken as a second offset into the string, counting from the end of the string.
OFFSET and LENGTH can be any arithmetic expression. The OFFSET starts at 0, not at 1.
e.g lets say the parameter is a string,
MYSTRING = "Be liberal in what you accept, and conservative in what you send"
echo ${MYSTRING:34:13}
The above will give you the following
conservative
as it will count the 33th(index start at 0) character which will start with the character "c" and then count (13 charcter) length .
So in your case $1 is the parameter you pass to your script and then it offsets 3 characters of that and take a string of length 1 and initialize it to x.
Read more here : http://wiki.bash-hackers.org/syntax/pe#substring_expansion
It is a GNU shell parameter expansion, part of many that start with ${.
Like ${parameter:-word}, ${parameter:=word}, ${parameter:?word}, ${parameter:+word} and several others.
This one (specific to ksh, bash and zsh): ${parameter:offset:length} extracts lenght characters (optional, if missing, the rest of the string in parameter) starting at offset. With several details described in the bash manual.
${name:offset:length}
Substring Expansion. Expands to up to length characters of the value of parameter starting at the character specified by offset. If parameter is #, an indexed array subscripted by # or *, or an associative array name, the results differ as described below. If length is omitted, expands to the substring of the value of parameter starting at the character specified by offset and extending to the end of the value. length and offset are arithmetic expressions (see ARITHMETIC EVALUATION below).
If offset evaluates to a number less than zero, the value is used as an offset in characters from the end of the value of parameter. If length evaluates to a number less than zero, it is interpreted as an offset in characters from the end of the value of parameter rather than a number of characters, and the expansion is the characters between offset and that result. Note that a negative offset must be separated from the colon by at least one space to avoid being confused with the :- expansion.
If parameter is #, the result is length positional parameters beginning at offset. A negative offset is taken relative to one greater than the greatest positional parameter, so an offset of -1 evaluates to the last positional parameter. It is an expansion error if length evaluates to a number less than zero.
If parameter is an indexed array name subscripted by # or *, the result is the length members of the array beginning with ${parameter[offset]}. A negative offset is taken relative to one greater than the maximum index of the specified array. It is an expansion error if length evaluates to a number less than zero.
Substring expansion applied to an associative array produces undefined results.
Substring indexing is zero-based unless the positional parameters are used, in which case the indexing starts at 1 by default. If offset is 0, and the positional parameters are used, $0 is prefixed to the list.
Use the manual page, all information is in there. man bash:
${parameter:offset:length}
Substring Expansion. Expands to up to length characters of the
value of parameter starting at the character specified by off‐
set. If parameter is #, an indexed array subscripted by # or *,
or an associative array name, the results differ as described
below. If length is omitted, expands to the substring of the
value of parameter starting at the character specified by offset
and extending to the end of the value. length and offset are
arithmetic expressions (see ARITHMETIC EVALUATION below).
What does x=${1:3:1} mean?
It's substring cut, and in English: using the string in $1, pull 1 character starting at index 3 (where indexes are 0-based). So if $1 === "foobar", then ${1:3:1} === "b".
I know that $1, $2 and $3 are arguments of the function. So does the above statement mean that x = $1:$2:$3?
No, adjacency represents string concatenation: x="$1$2$3" is the result of concatenating the strings in $1, $2, and $3.
Also, it is really helpful if someone can suggest on how do I google search for speacial characters like this? Any standard keywords? I tried searching 'what is ":" in shell scripts' etc.. But the results are random when trying to search for special characters.
bash parameter substitution usually gets you in the ballpark. I know I can't remember all the different syntax ways bash can fiddle with the data, so committing "parameter substitution" to memory pays off. String manipulation happens to be the chapter before parameter substitution.
Try this:
set ABCDEFG
echo ${1:3:1}
It is getting a substring. In general ${} refers to an array variable (in this case array of chars)

shell scripting passing 2D arrays to function

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
}

Complicated bash variable syntax

In one bash script i found the next construction:
if [[ "${xvar[id]:0:${#cnt}}" != "$cnt" ]]; then
Can someone explain what the above condition does?
The complicated expression is: ${xvar[id]:0:${#cnt}}.
$xvar must be an array, possibly associative. If it is associative, the part ${xvar[id]} refers to the element of the array identified by the string 'id'; if not, then it refers to the element indexed by variable $id (you're allowed to omit the nested $), as noted by chepner in a comment.
The ${xxx:0:${#cnt}} part of the expression refers to a substring from offset 0 to the length of the variable $cnt (so ${#cnt} is the length of the string in the variable $cnt).
All in all, the test checks whether the first characters of ${xvar[id]} are the same as the value of $cnt, so is the value in $cnt a prefix of the value in ${xvar[id]}.

Resources