Can't add another script in bash - bash

I wrote a bash script which calls another script in the same folder. I am doing this by simply putting ./email_pacotes.sh in the main script
#awk '{print $2}' >> /tmp/lista_pacotes.log adiciona resultado ao arquivo /tmp/tmp_pacotes_adicionados.log
echo "\nPacotes adicionados até" $(date) "\n" >> /tmp/tmp_pacotes_adicionados.log
cat /tmp/diferencas.log >> /tmp/tmp_pacotes_adicionados.log
./email_pacotes.sh
#adiciona resultados anteriores
cat /tmp/pacotes_adicionados.log >> /tmp/tmp_pacotes_adicionados.log
I thought that it was working correctly, but I had to debug the script for other reasons and I found out it wasn't adding the second script the first time a run the main script.
I was getting the following message:
[...]
./email_pacotes.sh: 17: ./email_pacotes.sh: [[: not found
./email_pacotes.sh: 17: ./email_pacotes.sh: [[: not found
./email_pacotes.sh: 17: ./email_pacotes.sh: [[: not found
./email_pacotes.sh: 17: ./email_pacotes.sh: [[: not found
./email_pacotes.sh: 17: ./email_pacotes.sh: [[: not found
[...]
This happens when I run the script the first time I put it in a folder. If I run it again, the message doesn't show anymore, so I guessing it is not a problem with the syntax. I also thought could be something with permissions, but I changed both scripts to 0777 and the message persists.
Is this a normal behaviour? What could be causing this?
Obs1: I am debugging the main script using the -x option.
Obs2: I made another test now. It keeps throwing the same message, but at certain point it finally calls the script. So maybe is just the time to find the file or throw a exception?

From the error, I'm pretty sure you're running the second script with a shell other than bash. The [[ ]] conditional is supported by bash (and zsh and maybe some other shells), but is not standard and there are other shells that don't support it. So if you want to use that (or any other nonstandard bash features), you need to use a proper shebang line in that script. Generally, that means you need to start the script with #!/bin/bash (or maybe #!/usr/bin/env bash), not with #!/bin/sh.
There's another thing that worries me, though. Running the second script with ./email_pacotes.sh will look for it in the current working directory, which is inherited from the process that ran the first script, and could be pretty much anywhere. If you want it to look for the second script in the same directory the first script is in, the best way is to locate the first script with something like "$(dirname "$BASH_SOURCE")" (and guess what -- BASH_SOURCE is a bash-only feature, so start the first script with a bash shebang as well). Then you can either refer to the second script (and any other relevant files) by explicit path:
#!/bin/bash
...
scriptDir="$(dirname "$BASH_SOURCE")"
if [[ ! -d "$scriptDir" ]]; then
echo "Something's terribly wrong; I can't find myself!" >&2
exit 1
fi
...
"$scriptDir/email_pacotes.sh"
or have the script cd to its own directory and then use relative paths:
#!/bin/bash
...
cd "$(dirname "$BASH_SOURCE")" || {
echo "Something's terribly wrong; I can't cd to my own directory!" >&2
exit 1
}
...
./email_pacotes.sh
I prefer the first approach, because if the any of the scripts accepts paths (e.g. as arguments), the user will expect those paths to be interpreted relative to where the user was when they ran the script, not relative to where the script itself is; cding in the script will break this.

Related

unix shell script unexpected error

when I run the following script
#!/bin/sh
[ `whoami` == root ] || echo "must be run as root"
I get the following error
./test.sh: 2: [: root: unexpected operator
How can I avoid that error?
While it might seem like the problem is not quoting the word root, your script does run without error on my machine, even without quoting it. So it seems your error depends on the shell implementation.
The problem is that sh is implemented by different shells in different environments. The posix sh command doesn't support == (only =), and I think that's the error you're experiencing. See e.g. this answer.
Try changing the first line to #!/bin/bash to see if this is the case on your machine.

Why is executing a ruby command on bash to command file not working?

Code from .command file:
cd "$(dirname "$0")"
g1=Hi-Lo
echo Welcome to Ruby_Games! So far, you can play $g1.
echo What game would you like to play?
read game_choice
if [$game_choice == $g1]
then
ruby Hi-Lo.rb
fi
Output:
Welcome to Ruby_Games! So far, you can play Hi-Lo.
What game would you like to play?
Hi-Lo
/Users/Abbas/Desktop/Ruby_Games/LAUNCHER.command: line 6: [Hi-Lo: command not found
logout
So what exactly is going wrong? Thanks
I believe you need double quotes in your if statement
Similar to example 6.4 here: http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-6.html
cd "$(dirname "$0")"
g1=Hi-Lo
echo Welcome to Ruby_Games! So far, you can play $g1.
echo What game would you like to play?
read game_choice
if [ "$game_choice" = "$g1" ]
then
ruby Hi-Lo.rb
fi
You need spaces between each element of the test (aka [) command. That is, you need a space between [ and $game_choice, between $game_choice and =, etc. Also, as #GregHNZ pointed out, you should use double-quotes around variable references, in case they contain spaces or certain other shell metacharacters. Finally, == in a test expression is a bash extension; use = instead, and it'll work in more basic shells as well. Result:
if [ "$game_choice" = "$g1" ]
Spaces are important delimiters in shell syntax; there are places they're required and places they're forbidden, and very very few places where they're optional. In many languages, you can add or remove spaces to make the code more readable, but that's not the case in shell.
BTW, I recommend using shellcheck.net; it does a pretty good job of spotting errors like this. Actually, it points out a couple I didn't think of: you should add a shebang line to the beginning of the script, and using cd without checking for an error risks the rest of the script running in an unexpected directory. So you should use something like this:
#!/bin/bash
cd "$(dirname "$0")" || {
echo "Error cd'ing to the script's directory" >&2
exit 1
}

Execute a line in Bash without aborting if it fails?

Is there a generic way in a bash script to "try" something but continue if it fails? The analogue in other languages would be wrapping it in a try/catch and ignoring the exception.
Specifically I am trying to source an optional satellite script file:
. $OPTIONAL_PATH
But when executing this, if $OPTIONAL_PATH doesn't exist, the whole script screeches to a halt.
I realize I could check to see if the file exists before sourcing it, but I'm curious if there is a generic reusable mechanism I can use that will ignore the error without halting.
Update: Apparently this is not normal behavior. I'm not sure why this is happening. I'm not explicitly calling set -e anywhere ($- is hB), yet it halts on the error. Here is the output I see:
./script.sh: line 36: projects/mobile.sh: No such file or directory
I added an echo "test" immediately after the source line, but it never prints, so it's not anything after that line that is exiting. I am running Mac OS 10.9.
Update 2: Nevermind, it was indeed shebanged as #!/bin/sh instead of #!/bin/bash. Thanks for the informative answer, Kaz.
Failed commands do not abort the script unless you explicitly configure that mode with set -e.
With regard to Bash's dot command, things are tricky. If we invoke bash as /bin/sh then it bails the script if the . command does not find the file. If we invoke bash as /bin/bash then it doesn't fail!
$ cat source.sh
#!/bin/sh
. nonexistent
echo here
$ ./source.sh
./source.sh: 3: .: nonexistent: not found
$ ed source.sh
35
1s/sh/bash/
wq
37
$ ./source.sh
./source.sh: line 3: nonexistent: No such file or directory
here
It does respond to set -e; if we have #!/bin/bash, and use set -e, then the echo is not reached. So one solution is to invoke bash this way.
If you want to keep the script maximally portable, it looks like you have to do the test.
The behavior of the dot command aborting the script is required by POSIX. Search for the "dot" keyword here. Quote:
If no readable file is found, a non-interactive shell shall abort; an interactive shell shall write a diagnostic message to standard error, but this condition shall not be considered a syntax error.
Arguably, this is the right thing to do, because dot is used for including pieces of the script. How can the script continue when a whole chunk of it has not been found?
Otherwise arguably, this is braindamaged behavior inconsistent with the treatment of other commands, and so Bash makes it consistent in its non-POSIX-conforming mode. If programmers want a command to fail, they can use set -e.
I tend to agree with Bash. The POSIX behavior is actually more broken than initially meets the eye, because this also doesn't work the way you want:
if . nonexistent ; then
echo loaded
fi
Even if the command is tested, it still aborts the script when it bails.
Thank GNU-deness we have alternative utilities, with source code.
You have several options:
Make sure set -e wasn't used, or turn it off with set +e. Your bash script should not exit by default simply because the . command failed.
Test that the file exists prior to sourcing.
[ -f "$OPTIONAL_PATH" ] && . "$OPTIONAL_PATH"
This option is complicated by the fact that if $OPTIONAL_PATH does not contain
any slashes, . will still try to find the file in your path.
If you want to keep set -e on, "hide" the failure like this:
. "$OPTIONAL_PATH" || true
Even if the source fails, the exit status of the command list as a whole will be 0, due to the || true.
(Much of this is covered [better] by Kaz's answer, especially the references to the POSIX standard, but I wasn't sure when or if he would undelete his answer.)
This is not the default behavior. Did you set -e or use #!/bin/bash -e anywhere in your script, to make it automatically exit on failure?
If so, you can use
. $OPTIONAL_PATH || true
to continue anyways.

Trouble Passing Parameter into Simple ShellScript (command not found)

I am trying to write a simple shell-script that prints out the first parameter if there is one and prints "none" if it doesn't. The script is called test.sh
if [$1 = ""]
then
echo "none"
else
echo $1
fi
If I run the script without a parameter everything works. However if I run this command source test.sh -test, I get this error -bash: [test: command not found before the script continues on and correctly echos test. What am I doing wrong?
you need spaces before/after '[',']' chars, i.e.
if [ "$1" = "" ] ; then
#---^---------^ here
echo "none"
else
echo "$1"
fi
And you need to wrap your reference (really all references) to $1 with quotes as edited above.
After you fix that, you may also need to give a relative path to your script, i.e.
source ./test.sh -test
#------^^--- there
When you get a shell error message has you have here, it almost always helps to turn on shell debugging with set -vx before the lines that are causing your trouble, OR very near the top your script. Then you can see each line/block of code that is being executed, AND the value of the variables that the shell is using.
I hope this helps.

bash script "unexpected end of file" in simple script

I have a script written in a file.
#!/bin/bash
if [ -f "/bin/uname" ]; then
OS=`/bin/uname`;
export OS="${OS}";
else
echo "Unable to detect OS - modify the appropriate .bashrc to support";
if
If I run it, I get the following error:
./temp.sh: line 9: syntax error: unexpected end of file
However, if I type the same script on bash prompt, it works.
(This piece of code is giving me nightmares. It is included in another large script which is failing due to these 6 lines. I put them in a separate script temp.sh and temp.sh gives the same error)!.
regards,
JP
Your last line should be fi instead of if.

Resources