This question already has answers here:
What is the difference between $(command) and `command` in shell programming?
(6 answers)
Closed 3 years ago.
I do not understand why the output is the username because in line 3 and 4 must print /usr/bin/whoami.
please explantation simple to me
#!/bin/bash
WHEREWHOAMI="`which whoami`"
ROOTORNOT="`$WHEREWHOAMI`"
echo "$ROOTORNOT"
The variable ROOTORNOT is set to the output of the execution of WHEREWHOAMI which in turn is the output of the command which whoami.
WHEREWHOAMI=`which whoami` # <- /usr/bin/whoami
ROOTWHOAMI="`$WHEREWHOAMI`" # <- `/usr/bin/whoami` # <- username
You can easily figure out what is going on if you add the set -x flag to your script. Example:
$ set -x
$ WHEREWHOAMI="`which whoami`"
++ alias
++ declare -f
++ /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot whoami
+ WHEREWHOAMI=/usr/bin/whoami
$ ROOTORNOT="`$WHEREWHOAMI`"
++ /usr/bin/whoami
+ ROOTORNOT=kvantour
$ echo "$ROOTORNOT"
+ echo kvantour
kvantour
$
Backticks are evaluated even inside double quotes.
(Suggestion - don't use backticks. use $() instead.)
WHEREWHOAMI="`which whoami`"
This executes which whoami and assigns /usr/bin/whoami to WHEREWHOAMI.
ROOTORNOT="`$WHEREWHOAMI`"
This executes /usr/bin/whoami in backticks, and assigns the USERNAME result to ROOTORNOT.
It's doing exactly what it should.
Is that not what you indended?
Perhaps what you wanted was something like -
$: [[ $( $(which whoami) ) == root ]] && echo ROOT || echo not-root
not-root
Though I do suggest storing the value and comparing that.
Is there a reason you can't just use
if [[ root == "$LOGNAME" ]]
then : ...
?
Related
This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 1 year ago.
The following code when run as an individual command in shell script gives the expected result :
for x in This is good; do echo $x; done
[OUTPUT]
This
is
good
However when i pass it inside a string to Eval for some reason x is not being initialised
cmd = " for x in This is good; do echo $x ; done"
eval $cmd
[OUTPUT]
//Three blank lines
Why is x not being initialised ?
Use single quotes to assign to cmd so $x isn't already consumed at assignment time.
Also, put double quotes around your argument to eval (the bugs it prevents are more subtle, and don't impact your current string, but when you do hit them they're serious).
cmd='for x in This is good; do echo "$x"; done'
eval "$cmd"
Note echo "$x" instead of echo $x -- see I just assigned a variable, but echo $variable shows something different!
This question already has answers here:
Remove a character from the end of a variable
(4 answers)
Closed 2 years ago.
In a bash file I get an input argument $1. It may contains a dot at its end or not like (test. or test)
I would like to have test in both cases to add an extension to it and create for example test.py from it
Parameter expansion has an operator % to trim characters from the end of an expansion.
$ set test.
$ echo "$1"
test.
$ echo "${1%.}"
test
If there is no trailing dot, the expansion is left unchanged:
$ set test
$ echo "${1%.}"
test
you can use parameter expansions like this :
yourVar=${1/.}
echo $yourVar
Result :
$ ./test.sh "test."
> test
$ ./test.sh "test"
> test
This question already has answers here:
How do I parse command line arguments in Bash?
(40 answers)
Closed 6 years ago.
hello all newbie here :D
i am working on a project right now which involves a script that handles a *.dat file.The script runs under specific commands inputed by user
my problem is that i cant figure out how to "grab" the arguments from the command to "import" them to the script
here are some examples from the specific commands :
./tool.sh -f <file>
./tool.sh -f <file> -id <id>
./tool.sh --born-since <dateA> --born-until <dateB> -f <file>
where tool.sh is the scripts name, <file> is the *.dat file, <date> is just a date in this format YYYY-MM-DD
so as you can see there are both shortwords and longwords. I know that the getopts command is tricky to handle the long ones. How can i handle all of them using a "single" piece of code?
edit: i need to use the arguments and the conditional expressions for a case using the "if"
so could i just do :
#!/bin/bash
getopts f a
if [ $1 == "something" && $2 == "something2" && $a == "f" ]; then
....
elif [ $1 == "something3" && $2 == "something4" && $a == "f" ]
....
else
....
fi
would that be correct?
In a bash script you can access command line arguments via order like so:
echo $1 # the first argument
echo $2 # the second argument
This question already has answers here:
Why can't I specify an environment variable and echo it in the same command line?
(9 answers)
Closed 2 years ago.
I saw codes like this:
fqdn='computer1.daveeddy.com'
IFS=. read hostname domain tld <<< "$fqdn"
echo "$hostname is in $domain.$tld"
# => "computer1 is in daveeddy.com"
I think it works because IFS is assigned to . in the third line.. So I tried this:
x=100 echo $x
but found the bash doesn't print anything, while I expect it will print 100..
Moreover, I found x=100 echo $x; echo $x print nothing, while x=100; echo $x prints 100, which is very confusing.
Does anyone have ideas about this?
The $x is expanded before echo runs, and the result is passed to echo as an argument. echo does not use the value of x in its environment.
In the first example, read uses the value of IFS in its environment to split the string it receives via the here string.
here is another way to think about it:
$ a="echo 100" $a
This is equal to:
$ a="echo 100"
Because at the time of scanning the line, $a is empty. Variable substition occurs first, so the $a just disappears.
Compare this to a very similar statment:
$ a="echo 100"; $a # returns "100"
For this problem I have two values, curdir and curlevel, which change throughout my script. I want to know if it's possible to create a variable and then use that value as the name for another value. For example
temp="dir_${curdir}_${curlevel}"
$temp=$name_of_directory **<----Is there a legitimate way to do this?**
so if initially curdir=1 and curlevel=0 then
$(temp)=directory_one
is equal to
dir_1_0=directory_one
then later if curdir=2 and curlevel=4, I can reset temp and then have
$(temp)=another_directory
is the same as
dir_2_4=another_directory
so I could make a call such as
cd $(temp)
which will move me to different directories when I need to
I think what you want is to use eval. Like so:
$ foo=bar
$ bar=baz
$ eval qux=\$$foo
$ echo $qux
baz
So what you could do is something like
eval temp=\$$"dir_${curdir}_${curlevel}"
cd $temp
The trick for this is to use eval - several times.
curdir=1
curlevel=0
temp='dir_${curdir}_${curlevel}' # Note single quotes!
x=$(eval echo $temp)
eval $x=$PWD
cd /tmp
curdir=2
curlevel=4
x=$(eval echo $temp)
eval $x=$PWD
echo $dir_1_0
echo $dir_2_4
The output of sh -x script:
+ curdir=1
+ curlevel=0
+ temp='dir_${curdir}_${curlevel}'
++ eval echo 'dir_${curdir}_${curlevel}'
+++ echo dir_1_0
+ x=dir_1_0
+ eval dir_1_0=/Users/jleffler/tmp/soq
++ dir_1_0=/Users/jleffler/tmp/soq
+ cd /tmp
+ curdir=2
+ curlevel=4
++ eval echo 'dir_${curdir}_${curlevel}'
+++ echo dir_2_4
+ x=dir_2_4
+ eval dir_2_4=/tmp
++ dir_2_4=/tmp
+ echo /Users/jleffler/tmp/soq
/Users/jleffler/tmp/soq
+ echo /tmp
/tmp
The output of sh script:
/Users/jleffler/tmp/soq
/tmp
Converted to a function:
change_dir()
{
temp='dir_${curdir}_${curlevel}' # Note single quotes!
x=$(eval echo $temp)
eval $x=$PWD
cd $1
}
curdir=1
curlevel=0
change_dir /tmp
curdir=2
curlevel=4
change_dir $HOME
echo $dir_1_0
echo $dir_2_4
pwd
Output:
/Users/jleffler/tmp/soq
/tmp
/Users/jleffler
The recorded names are the names of the directory being left, not the one you arrive at.
The secure way to do this is to use indirection, associative arrays (Bash 4), functions or declare:
Use declare:
declare $temp=$name_of_directory
Use indirection:
bar=42
foo=bar
echo ${!foo}
IFS= read -r $foo <<< 101
echo ${!foo}
Please take note of the security implications of eval.