How I can make alias called when it's called by a variable - linux

I added an alias:
$ alias anyalias="echo kallel"
If I execute:
$ anyalias
kallel
it executes the echo command without any problem.
Now, if I define a variable in this way:
$ var="anyalias"
and then execute with this way:
$ $var
-ash: anyalias: not found
Then I got a shell error.
How I can make $var running the command defined in the anyalias alias?
I m not looking to change the way of calling $var. But I m looking for a way of changing the definition of the alias or export it.

Instead of alias consider using function:
anyfunc() { echo "kallel"; }
v=anyfunc
$v
kallel
Safer is to store the call of function in an array (will store arguments also, if needed):
var=(anyfunc)
"${var[#]}"
kallel

That's because alias expansion is performed previous to parameter expansion:
Command-line Processing
As you can see, you can go through the process again with eval, which is not recommended.
Instead, you can use some alternatives as the one by #anubhava.
Example
$ alias anyalias="echo kallel"
$ var=anyalias
$ $var
bash: anyalias: command not found
$ eval $var
kallel
Again, use eval carefully. It's just to illustrate the expansion process.

Related

Unix, bad substitution error?

I have the following variables :
TYP=a1
STAT_a1=statistical
FINAL_VARIABLE=${STAT_${TYP}}
But I get an error:
-bash: ${STAT_${TYP}} : bad substitution
What I want is, that the value of FINAL_VARIABLE be 'statistical'
Please help..
You can't nest variable expansions like that. But you can use indirect variable expansion with ${!varname}:
TYP=a1
STAT_a1=statistical
STAT_var=STAT_${TYP} # This sets STAT_var to "STAT_a1"
FINAL_VARIABLE=${!STAT_var} # This sets FINAL_VARIABLE to "statistical"
BTW, I recommend avoiding all-caps variable names like TYP and FINAL_VARIABLE -- there are a number of all-caps names with special meanings to the shell and/or other programs, and if you accidentally use one of those weird things can happen.
Use eval, wrapping all the stuff you want to defer evaluating in single quotes:
eval 'FINAL_VARIABLE=${STAT_'${TYP}'}'
$ TYPE=al
$ STAT_a1=statistical
$ eval 'FINAL_VARIABLE=${STAT_'${TYP}'}'
$ echo $FINAL_VARIABLE
statistical
You can also do like this
root#myagent: tmp$ F=$(echo "${STAT_a1}"_"${TYP}")
root#myagent: tmp$ echo $F
statistical_a1

Using "read" to set variables

In bash from the CLI I can do:
$ ERR_TYPE=$"OVERLOAD"
$ echo $ERR_TYPE
OVERLOAD
$ read ${ERR_TYPE}_ERROR
1234
$ echo $OVERLOAD_ERROR
1234
This works great to set my variable name dynamically; in a script it doesn't work. I tried:
#!/bin/env bash
ERR_TYPE=("${ERR_TYPE[#]}" "OVERLOAD" "PANIC" "FATAL")
for i in "${ERR_TYPE[#]}"
do
sh -c $(echo ${i}_ERROR=$"1234")
done
echo $OVERLOAD_ERROR # output is blank
# I also tried these:
# ${i}_ERROR=$(echo ${i}_ERROR=$"1234") # command not found
# read ${i}_ERROR=$(echo ${i}_ERROR=$"1234") # it never terminates
How would I set a variable as I do from CLI, but in a script? thanks
When you use dynamic variables names instead of associative arrays, you really need to question your approach.
err_type=("OVERLOAD" "PANIC" "FATAL")
declare -A error
for type in "${err_type[#]}"; do
error[$type]=1234
done
Nevertheless, in bash you'd use declare:
declare "${i}_error=1234"
Your approach fails because you spawn a new shell, passing the command OVERLOAD_ERROR=1234, and then the shell exits. Your current shell is not affected at all.
Get out of the habit of using ALLCAPSVARNAMES. One day you'll write PATH=... and then wonder why your script is broken.
If the variable will hold a number, you can use let.
#!/bin/bash
ERR_TYPE=("OVERLOAD" "PANIC" "FATAL")
j=0
for i in "${ERR_TYPE[#]}"
do
let ${i}_ERROR=1000+j++
done
echo $OVERLOAD_ERROR
echo $PANIC_ERROR
echo $FATAL_ERROR
This outputs:
1000
1001
1002
I'd use eval.
I think this would be considered bad practice though (it had some thing to do with the fact that eval is "evil" because it allows bad input or something):
eval "${i}_ERROR=1234"

set default values for bash variables only if they were not previously declared

Here's my current process:
var[product]=messaging_app
var[component]=sms
var[version]=1.0.7
var[yum_location]=$product/$component/$deliverable_name
var[deliverable_name]=$product-$component-$version
# iterate on associative array indices
for default_var in "${!var[#]}" ; do
# skip variables that have been previously declared
if [[ -z ${!default_var} ]] ; then
# export each index as a variable, setting value to the value for that index in the array
export "$default_var=${var[$default_var]}"
fi
done
The core functionality I'm looking for is to set a list of default variables that will not overwrite previously declared variables.
The above code does that, but it also created the issue of these variables can now not depend on one another. This is because the ordering of the associative array's indices output from "${!var[#]}" is not always the same as the order they were declared in.
Does a simpler solution exist like:
declare --nooverwrite this=that
I haven't been able to find anything akin to that.
Also, I'm aware that this can be done with an if statement. However using a bunch of if statements would kill the readability on a script with near 100 default variables.
From 3.5.3 Shell Parameter Expansion:
${parameter:=word}
If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.
So
: ${this:=that}
: needed because otherwise the shell would see ${this:=that} as a request to run, as a command, whatever that expanded to.
$ echo "$this"
$ : ${this:=that}
$ echo "$this"
that
$ this=foo
$ echo "$this"
foo
$ : ${this:=that}
$ echo "$this"
foo
You can also to this the first place you use the variable (instead of on its own) if that suits things better (but make sure that's clear because it is easy to mess that up in later edits).
$ echo "$this"
$ echo "${this:=that}"
that
$ echo "$this"
that
Doing this dynamically, however, is less easy and may require eval.

dynamically creating bash variable and accessing its value defined earlier

i am trying to read the value of a bash variable defined earlier , but this variable name derived dynamically.
this is the bash script i am trying to do
$ mythreshold=10
$ table=my
$ threshold="$table"threshold
$ echo $("$threshold")
mythreshold
but when i try to read this variable value like
$ echo $("$threshold")
-bash: mythreshold: command not found
however i was expecting it to print
$ echo $("$threshold")
10
is there a way i can get this work, it should have printed the value of mythreshold variable defined above
$() is Command Substitution. It runs the command inside and returns the output. A variable name is not a command.
You can $(echo "$threshold") but that will only get the mythreshold back.
You need indirection for what you want. Specifically Evaluating indirect/reference variables.
As an example, for this specific case:
echo "${!threshold}"
Use eval command :
eval echo \${$threshold}
More details about this command can be found here:
eval command in Bash and its typical uses

concatenating aliases in linux shell

I would like to concatenate aliases. So for example, if I have the following:
alias aliasone="cat"
alias aliastwo="/etc/passwd"
I would like to be able to type in the shell something like "aliasone+aliastwo" and then the following command will be executed:
cat /etc/passwd
Can this be done?
Thanks!
Aliases are only for command substitution. If you want to have shorthand for arguments, use shell variables.
file=/etc/passwd
cat "$file"
Simply remove the "alias" from the second line. That is:
alias aliasone="cat"
folder="/etc/passwd"
And then you can write:
aliasone $folder
The problem is that alias evaluate commands; but in the second alias there is no command. In the case of a parameter is better to use a variable. If you have a more particular situation (e.g. you are are inside a script) tell us so we can give a better solution.
I think you are trying to run several aliases at the same time, one after another.
I might be wrong, but if this is the case, the easy solution will be to use && in a new alias.
For example you have two existing ones:
alias cdtomydir='cd /home/mydir'
alias listfilesindir = 'll'
then you are able to combine the two above into a third alias by using &&:
alias cdtomydirandlistfiles = 'cdtomydir && listfilesindir'
you can do this: alias aliasone='cat /etc/passwd' then just type aliasone and that's it then if you're going to use cat looking elsewhere then type alias aliastwo='cat /etc/shadow' for example. Anyway just change path and that's it and make sure that aliases are different and keep on mind that words used for commands aren't reserved.
Step 1:
alias ccat='cat $1'
Step 2:
ccat /etc/passwd
Output>>
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin.............

Resources