Assigning dynamic value to variable - shell

how can I assign a dynamic value to variable? The simplest method I know about is by using a function. For example
fn(){
VAR=$VAL
}
VAL=value
fn
echo $VAR
will output
value
but I want something simpler, like
VAR=$VAL
VAL=value
echo $VAR
to output
value
What command should I use? Preferably to be compatible with dash.
Thanks!
UPDATE: Removed #!/bin/sh in connection to dash. Thank "Ignacio Vazquez-Abrams" for the explanation!
UPDATE 2: Adding the source for my script to better understand the situation.
INPUT=`dpkg -l|grep ^rc|cut -d' ' -f3`
filter(){
echo *$A*
}
for A in $INPUT;do find ~ -iname `filter`|grep ^$HOME/\\.|grep -iz --color $A;done
This script should help finding the remaining configuration files of removed packages.

Okay, if function is not good, then maybe calling eval is okay?
export VAR='echo $VAL'
VAL=10
eval $VAR
This will display
10

How about a simple function that sets value?
# export is needed so f() can use it.
export VAR
f() {
VAR=$#
}
f 10
echo $VAR
f 20
echo $VAR
The code above will display:
10
20

If I understand your needs, you want an indirection, so try the following shell code (tested with dash) :
var=foo
x=var
eval $x=another_value
echo $var
output :
another_value
finally:
Each times you need to modify var, you need to run eval $x=foobar

Related

Shell Script msg() echo "${RED}$#${NOCOLOR}", What does it mean [duplicate]

Sometimes I have a one-liner that I am repeating many times for a particular task, but will likely never use again in the exact same form. It includes a file name that I am pasting in from a directory listing. Somewhere in between and creating a bash script I thought maybe I could just create a one-liner function at the command line like:
numresults(){ ls "$1"/RealignerTargetCreator | wc -l }
I've tried a few things like using eval, using numresults=function..., but haven't stumbled on the right syntax, and haven't found anything on the web so far. (Everything coming up is just tutorials on bash functions).
Quoting my answer for a similar question on Ask Ubuntu:
Functions in bash are essentially named compound commands (or code
blocks). From man bash:
Compound Commands
A compound command is one of the following:
...
{ list; }
list is simply executed in the current shell environment. list
must be terminated with a newline or semicolon. This is known
as a group command.
...
Shell Function Definitions
A shell function is an object that is called like a simple command and
executes a compound command with a new set of positional parameters.
... [C]ommand is usually a list of commands between { and }, but
may be any command listed under Compound Commands above.
There's no reason given, it's just the syntax.
Try with a semicolon after wc -l:
numresults(){ ls "$1"/RealignerTargetCreator | wc -l; }
Don't use ls | wc -l as it may give you wrong results if file names have newlines in it. You can use this function instead:
numresults() { find "$1" -mindepth 1 -printf '.' | wc -c; }
You can also count files without find. Using arrays,
numresults () { local files=( "$1"/* ); echo "${#files[#]}"; }
or using positional parameters
numresults () { set -- "$1"/*; echo "$#"; }
To match hidden files as well,
numresults () { local files=( "$1"/* "$1"/.* ); echo $(("${#files[#]}" - 2)); }
numresults () { set -- "$1"/* "$1"/.*; echo $(("$#" - 2)); }
(Subtracting 2 from the result compensates for . and ...)
You can get a
bash: syntax error near unexpected token `('
error if you already have an alias with the same name as the function you're trying to define.
The easiest way maybe is echoing what you want to get back.
function myfunc()
{
local myresult='some value'
echo "$myresult"
}
result=$(myfunc) # or result=`myfunc`
echo $result
Anyway here you can find a good how-to for more advanced purposes

read multiple values from a property file using bash shell script

Would like to read multiple values from a property file using a shell script
My properties files looks something like below, the reason I added it following way was to make sure, if in future more students joins I just need to add in in the properties file without changing any thing in the shell script.
student.properties
total_student=6
student_name_1="aaaa"
student_name_2="bbbb"
student_name_3="cccc"
student_name_4="dddd"
student_name_5="eeee"
When I run below script I not getting the desired output, for reading the student names from properties file
student.sh
#!/bin/bash
. /student.properties
i=1
while [ $i -lt $total_student ]
do
{
std_Name=$student_name_$i
echo $std_Name
#****** my logic *******
} || {
echo "ERROR..."
}
i=`expr $i + 1`
done
Output is something like this
1
2
3
4
5
I understand the script is not getting anything for $student_name_ hence only $i value is getting printed.
Hence, wanted to know how to read values from the properties file.
You can do variable name interpolation with ${!foo}. If $foo is "bar", then ${!foo} gives you the value of $bar. In your code that means changing
std_Name=$student_name_$i
to
var=student_name_$i
std_Name=${!var}
Alternatively, you could store the names in an array. Then you wouldn't have to do any parsing.
student.properties
student_names=("aaaa" "bbbb" "cccc" "dddd" "eeee")
student.sh
#!/bin/bash
. /student.properties
for student_name in "${student_names[#]}"; do
...
done
You can use indirect expansion:
std_Name=student_name_$i
echo "${!std_Name}"
the expression ${!var} basically evaluates the variable twice:
first evaluation: student_name_1
second evaluation: foo
Note that this is rarely a good idea and that using an array is almost always preferred.

Bash: iterate through files based on regex parameter

There are several posts about iterating through bash files like this:
count_files() {
count=0
for f in "filename_*.txt"
do
count=$(($count + 1))
done
echo "Current count:$count"
}
I need to pass in "filename_*.txt" as a param when calling the bash script. Like this:
$: count_files.sh "filename_*.txt"
$: count_files.sh "different_filename_*.txt"
This, however, only gets the first file:
count_files() {
count=0
for f in $1
do
count=$(($count + 1))
done
echo "Current count:$count"
}
How do I pass in a regex param and iterate through it?
NOTE: counting the files is just an example. If you have a simple way to do that, please share, but that's not the main question.
Inside count_files.sh script make sure you call function with quotes like this:
count_files "$1"
instead of:
count_files $1
Later will get you count=1 because wildcard will be expanded before function call to the first file name.

atoi() like function in bash?

Imagine that I use a state file to store a number, I read the number like this:
COUNT=$(< /tmp/state_file)
But since the file could be disrupted, $COUNT may not contain a "number", but any characters.
Other than using regex, i.e if [[ $COUNT ~ ^[0-9]+$ ]]; then blabla; fi, is there a "atoi" function that convert it to a number(0 if invalid)?
EDIT
Finally I decided to use something like this:
let a=$(($a+0))
Or
declare -i a; a="abcd123"; echo $a # got 0
Thanks to J20 for the hint.
You don't need an atoi equivalent, Bash variables are untyped. Trying to use variables set to random characters in arithmetic will just silently ignore them. eg
foo1=1
foo2=bar
let foo3=foo1+foo2
echo $foo3
Gives the result 1.
See this reference
echo $COUNT | bc should be able to cast a number, prone to error as per jurgemaister's comments...
echo ${COUNT/[a-Z]*} | bc which is similar to your regex method but not prone to error.
case "$c" in
[0-9])...
You should eat the input string charwise.

Check size of string and depending on size, manipulate it?

I have tried dong this my self but I have failed miserably, but this is basically what I am trying to achieve in sh (#!/bin/sh):
sudo code
SOMEVAR="VALUE"
if [ $SOMEVAR.length > 5]
then
# Take the first 5 characters of the string and add "HIS" to the end of them, assigning this new value to the SOMEVAR variable.
else
#just add "HIS" to the end of the string
fi
if someone can tell me how i can achieve this it would be greatly appreciated, I have tried using ${#SOMEVAR} > 5 and ${SOMEVAR:0:5} but this dosnet work for me.
thanks
To have it work in Bourne, you can use:
#!/bin/sh
SOMEVAR="HELLO WORLD"
if [ ${#SOMEVAR} -gt 5 ]
then
SOMEVAR=`expr substr "$SOMEVAR" 1 5`
fi
SOMEVAR="${SOMEVAR}HIS"
You're probably using a version of Bourne that can do this in one line without invoking any other commands like expr:
SOMEVAR=${SOMEVAR:0:5}HIS
But if your shell doesn't support that fancy substring extraction syntax, you could use sed. (Note that not all versions of expr support substr.)
SOMEVAR=`echo "$SOMEVAR" | sed 's/^\(.....\).*/\1/'`HIS

Resources