I know I can use this:
SHELL := /bin/bash
And make will use /bin/bash shell. Can I do the same with echo command? For example:
SHELL := /bin/bash
ECHO := /bin/echo -e
all:
#echo Fixed echo?
I always thought that using ECHOCMD := /bin/echo -e on the top of my Makefile would do this. But after searching, I could not find any reference supporting that ECHOCMD := /bin/echo -e has any special meaning to change the default #echo command.
Is the only alternative to use:
SHELL := /bin/bash
ECHO := /bin/echo -e
all:
#${ECHO} Fixed echo?
Related
I am trying to run a bash script that has parameters like so:
./test.sh param1 param2
bash file
param1=$1
param2=$2
echo $param1
echo $param2
However it does not work but it will work if the params are not there.
cmd, _ := exec.Command("/bin/sh", fmt.Sprintf("./test.sh %s %s","test1","test2")).Output()
But if I change the bash script to do something else without passing anything into it, then it works.
cmd, _ := exec.Command("/bin/sh", "./test.sh").Output()
How can I pass parameters into a bash file with Go?
sh expects the name of a script to run as its argument. You don't run sh './test.sh test1 test2' at a shell, you run sh ./test.sh test1 test2. The equivalent to that in Go is:
// KINDA BAD: Doesn't let the script choose its own interpreter
cmd, err := exec.Command("/bin/sh", "./test.sh", "test1", "test2")
If you were passing a shell script as an argument, that would be akin to the shell command sh -c './test.sh test1 test2' -- notice the -c argument. It's very bad practice (introduces serious security bugs), and you shouldn't ever do this, but if you were going to, it would look like:
// VERY BAD: Introduces serious security bugs if arguments are parameterized
cmd, err := exec.Command("/bin/sh", "-c", "./test.sh test1 test2")
But you shouldn't do any of that. Change your script to have a shebang:
#!/bin/sh
param1=$1
param2=$2
echo "$param1"
echo "$param2"
...save it as yourscript (no .sh!), set it to have executable permissions (chmod +x yourscript), and then run:
// GOOD: Lets your script choose its own interpreter
cmd, err := exec.Command("./yourscript", "test1", "test2")
I want to echo a string into the /etc/hosts file. The string is stored in a variable called $myString.
When I run the following code the echo is empty:
finalString="Hello\nWorld"
sudo bash -c 'echo -e "$finalString"'
What am I doing wrong?
You're not exporting the variable into the environment so that it can be picked up by subprocesses.
You haven't told sudo to preserve the environment.
\
finalString="Hello\nWorld"
export finalString
sudo -E bash -c 'echo -e "$finalString"'
Alternatively, you can have the current shell substitute instead:
finalString="Hello\nWorld"
sudo bash -c 'echo -e "'"$finalString"'"'
You can do this:
bash -c "echo -e '$finalString'"
i.e using double quote to pass argument to the subshell, thus the variable ($finalString) is expanded (by the current shell) as expected.
Though I would recommend not using the -e flag with echo. Instead you can just do:
finalString="Hello
World"
What is a procedure to decorate an arbitrary bash command to execute it in a subshell? I cannot change the command, I have to decorate it on the outside.
the best I can think of is
>bash -c '<command>'
works on these:
>bash -c 'echo'
>bash -c 'echo foobar'
>bash -c 'echo \"'
but what about the commands such as
echo \'
and especially
echo \'\"
The decoration has to be always the same for all commands. It has to always work.
You say "subshell" - you can get one of those by just putting parentheses around the command:
x=outer
(x=inner; echo "x=$x"; exit)
echo "x=$x"
produces this:
x=inner
x=outer
You could (ab)use heredocs:
bash -c "$(cat <<-EOF
echo \'\"
EOF
)"
This is one way without using -c option:
bash <<EOF
echo \'\"
EOF
What you want to do is exactly the same as escapeshellcmd() in PHP (http://php.net/manual/fr/function.escapeshellcmd.php)
You just need to escape #&;`|*?~<>^()[]{}$\, \x0A and \xFF. ' and " are escaped only if they are not paired.
But beware of security issues...
Let bash take care of it this way:
1) prepare the command as an array:
astrCmd=(echo \'\");
2) export the array as a simple string:
export EXPORTEDastrCmd="`declare -p astrCmd| sed -r "s,[^=]*='(.*)',\1,"`";
3) restore the array and run it as a full command:
bash -c "declare -a astrCmd='$EXPORTEDastrCmd';\${astrCmd[#]}"
Create a function to make these steps more easy like:
FUNCbash(){
astrCmd=("$#");
export EXPORTEDastrCmd="`declare -p astrCmd| sed -r "s,[^=]*='(.*)',\1,"`";
bash -c "declare -a astrCmd='$EXPORTEDastrCmd';\${astrCmd[#]}";
}
FUNCbash echo \'\"
$ sudo sh -c "FOO=bar echo Result:${FOO}"
Result:
Why is the value stored in FOO not displayed?
Because bash replaces ${FOO} before calling sudo. So what sh -c actually sees is:
FOO=bar echo Result:
Besides, even if you tried
FOO=bar echo Result:${FOO}
It still won't work1. To get that right, you can do:
FOO=bar; echo Result:${FOO}
Now that that is fixed, let's get back to sh -c. To prevent bash from interpreting the string you are giving to sh -c, simply put it in ' instead of ":
sudo sh -c 'FOO=bar; echo Result:${FOO}'
1 Refer to the comments for reason.
This doesn't work, because the variable FOO is set for the following command, echo, but the ${FOO} is replaced by the enclosing shell.
If you want it to work, you must set the variable FOO for the enclosing shell and wrap the echo ... in single quotes
sudo FOO=bar sh -c 'echo Result:${FOO}'
My colleague use Ubuntu and I use openSUSE, we compiled same source code using same makefile, my environment works well, but my colleague can't, always output the can't recognized -e option. We check the makefile, ONLY find echo command use -e option.
Dose Ubuntu's echo function is different with others?
+++++update
in makefile, the echo define as:
TOOLSDIR =
ECHO = $(TOOLSDIR)echo -e
The $(TOOLSDIR) is dir for tool, this make file can detect compile env, if linux or has CYGWIN:
$(TOOLSDIR)is empty, if windows, it will goes to WIN32 version echo tool dir, like:
TOOLSDIR = $(subst /,\,$(MAKEDIR)/tools/WIN32/)
after we execute make, ubuntu will output:
Fatal error: L3900U: Unrecognized option '-e'.
however, openSUSE doesn't have this error
+++++update for echo -e
I write a test makefile in ubuntu
all:
echo -e hello
it output:
echo -e hello
hello
+++++update makefile test in openSUE (12.1) and ubuntu (12.04)
all:
echo -e "hello 1"
echo -e hello 2
echo -e he\nllo3
echo -e "he\nllo4"
opensuse, the output is:
echo -e "hello 1"
hello 1
echo -e hello 2
hello 2
echo -e he\nllo3
henllo3
echo -e "he\nllo4"
he
llo4
in ubuntu, the output is:
echo -e "hello 1"
-e hello 1
echo -e hello 2
hello 2
echo -e he\nllo3
henllo3
echo -e "he\nllo4"
-e he
llo4
Meanwhile, i test in ubuntu, echo without -e, the result is same as in openSUSE, echo with -e
It could depend from the shell you guys are using (echo is often implemented inside the shell)
this is what happens in OS X (Mountain Lion):
$ bash
bash-4.2$ echo -e foo
foo
bash-4.2$ sh
sh-3.2$ echo -e foo
-e foo
The same for OpenSUSE, and Ubuntu.
-e option is not compliant to POSIX (I'm not sure, but it should be the default behavior), btw, to print formatted text, printf is more appropriate command.
From the information you provide, it looks to me that your makefile has a bug (portability issue).
On OSX man echo doesn't list the -e option too, btw. On Ubuntu 12.10 the -e is present on my computer, on my router BusyBox v1.13.4 also accepts the -e (it's internal command for busybox)
But probably it's just the /bin/sh using internal command and ignoring it.
==== UPDATE:
In your makefile remove the $(TOOLSDIR) in front of echo:
ECHO = echo -e
in fact if you specify the path of the echo (i.e. /bin/echo) you force the shell to execute the program from the filesystem instead of the one implemented internally by the shell:
$ echo -e foo
foo
$ /bin/echo -e foo
-e foo
I also find it may cause by ubuntu link /bin/sh to dash but NOT bash. After I use bash, problem solved and there is an other question related to this, which I asked:
same shell script has different behaviou on different Linux distribution
Both Luigi R. Viggiano and How Chen provide good explanations to the problem and solutions to it. In fact, their answers complement each other.
In dash, the echo command does not accept the -e flag. However, in bash, it does.
In Ubuntu, one might consider using update-alternatives to select bash, rather than dash, as the default shell. The following commands will do the trick (warning, these commands will apply system-wide):
sudo update-alternatives --install /bin/sh sh /bin/bash 0
sudo update-alternatives --install /bin/sh sh /bin/dash 0
sudo update-alternatives --set sh /bin/bash
The \ is the escape character in the shell, so \n is just that, an "n", so escape the escape \\\n.
[sg#Study ~]$ echo -e \\nfoo\\nfoo
foo
foo
[sg#Study ~]$
or use quotes
[sg#Study ~]$ echo -e "\\nfoo\\nfoo"
foo
foo
[sg#Study ~]$