Shell script: call command containing variable - bash

What is wrong with this script?
#!/bin/sh
SONAR="~/SonarQube/bin/linux-x86-64/sonar.sh"
echo "Waiting to start..."
$($SONAR start)
It says ./start.sh: 4: ./start.sh: ~/SonarQube/bin/linux-x86-64/sonar.sh: not found but it does exist. I tried a huge amount of variations it does work only with eval: eval $SONAR start.

Try this instead :
#!/bin/sh
SONAR=~/"SonarQube/bin/linux-x86-64/sonar.sh"
echo "Waiting to start..."
"$SONAR" start
Tilde expansion is disabled by quoting (like globbing), so you need to put the tilde outside the quotes.
The last line should not be inside $(), as doing this first executes the command, and then expands the content and tries to execute a commande expressed by such content.

Scripts usually use $HOME instead of ~. $HOME will expand even inside double quotes.
#!/bin/sh
SONAR="$HOME/SonarQube/bin/linux-x86-64/sonar.sh"
echo "Waiting to start..."
"$SONAR" start

You're using the ~ between doublequotes, so it's not going to be interpreted as /home/whatever.
#!/bin/sh
SONAR=~/SonarQube/bin/linux-x86-64/sonar.sh

Related

Can't seem to escape a space in a shell script [duplicate]

What is the correct way to call some command stored in variable?
Are there any differences between 1 and 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Unix shells operate a series of transformations on each line of input before executing them. For most shells it looks something like this (taken from the Bash man page):
initial word splitting
brace expansion
tilde expansion
parameter, variable and arithmetic expansion
command substitution
secondary word splitting
path expansion (aka globbing)
quote removal
Using $cmd directly gets it replaced by your command during the parameter expansion phase, and it then undergoes all following transformations.
Using eval "$cmd" does nothing until the quote removal phase, where $cmd is returned as is, and passed as a parameter to eval, whose function is to run the whole chain again before executing.
So basically, they're the same in most cases and differ when your command makes use of the transformation steps up to parameter expansion. For example, using brace expansion:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
If you just do eval $cmd when we do cmd="ls -l" (interactively and in a script), you get the desired result. In your case, you have a pipe with a grep without a pattern, so the grep part will fail with an error message. Just $cmd will generate a "command not found" (or some such) message.
So try use to eval (near "The args are read and concatenated together") and use a finished command, not one that generates an error message.
$cmd would just replace the variable with it's value to be executed on command line.
eval "$cmd" does variable expansion & command substitution before executing the resulting value on command line
The 2nd method is helpful when you wanna run commands that aren't flexible eg.
for i in {$a..$b} format loop won't work because it doesn't allow variables. In this case, a pipe to bash or eval is a workaround.
Tested on Mac OSX 10.6.8, Bash 3.2.48
I think you should put
`
(backtick) symbols around your variable.

Terminal program: unable to find the directory/file though they are in the correct pathway

What else could be going wrong? Sorry I'm pretty new to programming so I'm not sure if this is the proper way to frame my question.
Here is the code from the terminal file:
echo "Patcher Coded by _Retro_"
PLACE=`dirname $0`
ROM=`ls ${PLACE}/Rom/*.nds | head -n 1`
PATCH=`ls ${PLACE}/Patch/*.* | head -n 1`
NAME=${ROM%.[^.]*}
$PLACE/xdelta3 -dfs $ROM $PATCH $NAME-patched.nds
Your script says this:
PLACE=`dirname $0`
First, the shell performs parameter expansion. That means (in this case) it expands $0. The variable $0 expands to the path used by the shell to execute your script, so that line expands to this:
PLACE=`dirname /Users/ShakeyBanks/Desktop/Perfect Heart CE./DS_Rom_Patcher/Rom_Patcher`
Note that there are no backslashes in the expansion! The backslashes were consumed by your interactive shell before starting the script.
Then the shell performs command substitution: it executes the command enclosed in `...`. The shell splits the command on spaces, so the command contains four words. The first word is the program to run, and the remaining three words are arguments to that command:
dirname
/Users/ShakeyBanks/Desktop/Perfect
Heart
CE./DS_Rom_Patcher/Rom_Patcher
The problem here is that the dirname program only wants one argument, but you're passing it three. It detects this and fails with an error:
usage: dirname path
To fix this, quote the $0 with double-quotes, like this:
PLACE=`dirname "$0"`
You also need to quote all subsequent uses of $PLACE, ${PLACE}, $ROM, $PATCH, and $NAME with double-quotes, because they will have the same problem.
OR, rename your directory to not contain spaces.

Bash 'xargs' and 'stat' behaviour as variable [duplicate]

What is the correct way to call some command stored in variable?
Are there any differences between 1 and 2?
#!/bin/sh
cmd="ls -la $APPROOTDIR | grep exception"
#1
$cmd
#2
eval "$cmd"
Unix shells operate a series of transformations on each line of input before executing them. For most shells it looks something like this (taken from the Bash man page):
initial word splitting
brace expansion
tilde expansion
parameter, variable and arithmetic expansion
command substitution
secondary word splitting
path expansion (aka globbing)
quote removal
Using $cmd directly gets it replaced by your command during the parameter expansion phase, and it then undergoes all following transformations.
Using eval "$cmd" does nothing until the quote removal phase, where $cmd is returned as is, and passed as a parameter to eval, whose function is to run the whole chain again before executing.
So basically, they're the same in most cases and differ when your command makes use of the transformation steps up to parameter expansion. For example, using brace expansion:
$ cmd="echo foo{bar,baz}"
$ $cmd
foo{bar,baz}
$ eval "$cmd"
foobar foobaz
If you just do eval $cmd when we do cmd="ls -l" (interactively and in a script), you get the desired result. In your case, you have a pipe with a grep without a pattern, so the grep part will fail with an error message. Just $cmd will generate a "command not found" (or some such) message.
So try use to eval (near "The args are read and concatenated together") and use a finished command, not one that generates an error message.
$cmd would just replace the variable with it's value to be executed on command line.
eval "$cmd" does variable expansion & command substitution before executing the resulting value on command line
The 2nd method is helpful when you wanna run commands that aren't flexible eg.
for i in {$a..$b} format loop won't work because it doesn't allow variables. In this case, a pipe to bash or eval is a workaround.
Tested on Mac OSX 10.6.8, Bash 3.2.48
I think you should put
`
(backtick) symbols around your variable.

child script eval and ${#} differences

I have a parent script
while read cmd
do
nohup ./script ${cmd[#]} &>> log &
done < ~/list
that executes this child script
while true
do
eval "${CMD[#]}"
#${CMD[#]}
#./panic
done
with this list of commands
node ~/www/splash/app.js
node ~/www/splash-two/app.js
When the child script calls
eval ${CMD[#]}
it executes the way I expect running that command with no complaints but when I try to remove the eval and run the command using
${CMD[#]}
It throws the error
Error: Cannot find module '/home/rumplefraggle/SYS/RABBOT/~/www/splash/app.js'
Now I thought possibly this had something to do with the node command so I tried to execute
ls ~
as the command and it throws the error that ~ can not be found.
Echoing ${#} and not running it expands as I would expect it to.
Also manually inserting the command into the child script also works as expected
I don`t understand why eval works and simply running the command using ${#} does not. What is causing ${#} to not expand the ~ ?
Why is node appending the directory name to the command when ${#} is used?
Because bash first expands tilde and then the variables. node is not the one expanding the variable. You should stick with eval or use ${HOME} in your commands.
The expansion order is like this: brace expansion, tilde expansion, parameter, variable, and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and filename expansion

printing the ampersand

I have a bash script that takes a url with variables and writes it to a file, problem is the ampersand is interfering and being interpreted as a command / control character.
In this situation the string cannot be escaped BEFORE being passed to the script and I have yet to find any way to do this.
if [ $1 ] ; then
url=$1
printf %q "$url" > "/somepath/somefile"
fi
with $1 being for example localhost?x=1&y=2&z=3
What get's printed is only the part before the first ampersand: "localhost?x=1"
I have also tried echo instead of printf but it's exactly the same ??
Your script is fine, but you need to invoke the script with a quoted parameter:
./myscript.sh "localhost?x=1&y=2&z=3"
There is no problem with echo nor print. The problem is that when you run the script, it starts those 2 jobs in background. For more information you can check: http://hacktux.com/bash/ampersand.
You can simply start script with 'localhost?x=1&y=2&z=3' in apostrophes, so bash will not treat ampersand as operator but just as normal character.
Quote things. Replace all $1s with "$1"s. And quote argument when you actually invoke your script.

Resources