bash config syntax error - bash

I'm setting up a brand new VPS on Bluehost. As soon as I logged in, I knew something was amiss. When I launch a bash shell I get this error:
bash: eval: line 9: syntax error: unexpected end of file
I tracked the problem down to the line eval $(perl -Mlocal::lib) in /etc/profile.d/locallib.sh:
#cPanel Added local::lib -- BEGIN
LOCALLIBUSER=$USER
if [ -e "/usr/bin/whoami" ]; then
LOCALLIBUSER=`/usr/bin/whoami`
fi
if [ "$LOCALLIBUSER" != "root" ]; then
eval $(perl -Mlocal::lib)
fi
#cPanel Added local::lib -- END
When I execute eval $(perl -Mlocal::lib) at the bash prompt, I get the error bash: syntax error: unexpected end of file. When I execute perl -Mlocal::lib at the bash prompt I get this:
if ! $?PERL_MB_OPT setenv PERL_MB_OPT '';
setenv PERL_MB_OPT "--install_base "\""/home/MYUSERNAME/perl5"\""";
if ! $?PERL_MM_OPT setenv PERL_MM_OPT '';
setenv PERL_MM_OPT "INSTALL_BASE=/home/MYUSERNAME/perl5";
Why am I getting this error? How do I correct it? I'm relatively new to bash and utterly hopeless with perl, so am on shaky ground here. Thanks!

The code inside local::lib is misidentifying your shell as csh for some reason. You can force it with --shelltype bourne according to the documentation.
eval $(perl -Mlocal::lib=--shelltype,bourne)
I'm speculating that your account may have been set up with tcsh as your default shell. You can change this permanently with chsh, in which case this workaround should hopefully not be necessary.

Related

Cron doesn't accept bash syntax

I have a bashscript that I'm running with crontab. Unfortunately, a script that works fine when run manually fails with the error:
Syntax error: "(" unexpected (expecting "}")
Where the line in question is line 22 which is:
declare -a PREV_TOTAL=( $(for i in ${range[#]}; do echo 0; done) )
In the larger context:
TOTAL_CPU_USAGE=0
TOTAL_CPU=$(grep -c ^processor /proc/cpuinfo) #set number of CPUs to check for
declare -a 'range=({'"0..$TOTAL_CPU"'})'
let "TOTAL_CPU=$TOTAL_CPU - 1"
#declare array of size TOTAL_CPU to store values (eg. 8 cpus makes arrays of size 8)
declare -a PREV_TOTAL=( $(for i in ${range[#]}; do echo 0; done) )
declare -a PREV_IDLE=( $(for i in ${range[#]}; do echo 0; done) )
This works when manually just fine, but I don't understand what I'm doing wrong that causes cron to give this error? If you know I'd be very appreciative. Thanks.
EDIT: My crontab looks like this:
# m h dom mon dow command
SHELL=/bin/bash
#reboot cd /home/ubuntu/waste-cloud-computing/probe && probe.sh >> /var/log/somelogfile.log 2>&1
And I access it with sudo crontab -e. I'm still getting the issue while providing the SHELL variable.
EDIT 1: Thanks to some help I got past the syntax issues by ensuring the shell was using bash. Now I get the error, /bin/bash: probe.bash: command not found. I assume its some kind of PATH issue, but which bash returns /bin/bash so it seems normal to me. Maybe someone knows what's up?
cron jobs are run by sh by default, not bash. If you are using ubuntu/vixiecron, you can set the SHELL env variable at the top of the crontab to make cron run the commands in your crontab with bash.
SHELL=/bin/bash
If the script you want to be run is a bash script, make sure you have a shebang at the first line:
#!/bin/bash
Also note that there will be other potential troubleshooting steps if your scripts depend on a particular user's profile, env vars, etc. depending on which crontab you are editing.
Thanks to the help of the people here I found my issue was not syntax but rather the use of sh over bash. This was fixed by setting the crontab this way so future users can see:
# m h dom mon dow command
SHELL=/bin/bash
#reboot cd /home/ubuntu/waste-cloud-computing/probe && ./probe.sh >> /var/log/somelogfile.log 2>&1
The key points are the SHELL variable being set and the ./ before running the script.

bash script to run ./configure from sudo

I am using GNU bash, version 3.2.51(1)-release (sparc-sun-solaris2.10) on Solaris and trying to write a bash script to configure/compile sudo after doing a few other items. Essentially I want to be able to have operators run this script so they can install sudo from source by just running this script and not having to worry about running ./configure with options and make, etc..
It appears it works up until the config.status libtool part and then it dies with:
: creating pathnames.h config.status: pathnames.h is unchanged config.status: executing libtool commands
./install_sudo.sh: line 55: configure:: command not found
install_sudo.sh is my script which basically just untar's sudo and sets up the path. It then runs a function ConfigureSudo:
here is the script now that is not working with the above error:
#!/usr/bin/bash
Unpack(){
SRCA="sudo-1.8.7.tar.gz"
SRCB="sudo-1.8.7.tar"
if [ -f $PWD/$SRCA ]; then
echo "sudo source appears to be here!"
`/usr/bin/gunzip "$SRCA"`
`/usr/bin/tar xf "$SRCB"`
else
echo "Check your source file."
fi
}
SetupPath(){
echo "Setting up path to use included Solaris software..."
echo "Current PATH is $PATH"
PATH=/usr/sfw/bin:/usr/sfw/sbin:/usr/sfw/sparc-sun-solaris2.10/bin:$PATH
echo "Now set to $PATH"
}
ConfigureSudo(){
dir="/tmp/sudo-1.8.7"
arg1="--prefix=/usr/local"
arg2="--sysconfdir=/etc"
arg3="--localstatedir=/var/run/sudo"
arg4="--with-pam"
arg5="--with-timedir=/var/lib/sudo"
cmd=configure
$($dir/$cmd $arg1 $arg2 $arg3 $arg4 $arg5)
}
Unpack
SetupPath
ConfigureSudo
Any help to get past with is greatly appreciated.
TIA!
Jeff
$($dir/$cmd $arg1 $arg2 $arg3 $arg4 $arg5)
You don't need to place that inside process substitution I think. Its output would be executed as well. You should also quote your variables properly.
"$dir/$cmd" "$arg1" "$arg2" "$arg3" "$arg4" "$arg5"
One suggestion would be to place the line:
set -x
immediately after the shebang line (line #1) so that commands are echoed before being executed.
That will show you any problematic expansions that are happening and may lead you to the problem.
You may also need to put it at the start of each function, I can't remember whether it carries forward into functions or not. But try it at the top of the script first.

shell script error status and syntax checking

I have written a shell script and I am using few commands like rm, ls, etc. In case where those commands fails , I am checking the return status '$?' . But If the script has some syntax error, how can I get the error status of it ? Basically I am going to source this script from another script using the 'source' command. So if the script which is sourced has any syntax error I want to display that in console. Is there any way to get that status ? In shell I executed the script with syntax error and I got the error like 'missing [' , but when I executed echo $? its returning 0 as the status, is this the behavior ? How can I get the status if the script has some syntax error or not ?
You can check the syntax of a shell script using the -n option prior to sourcing:
bash -n somescript # Works also for sh, ksh, zsh et al.
will tell you if somescript is syntactically okay without actually running it. In a program:
if bash -n somescript; then
. somescript
else
printf '%s\n' "Uh-oh, somescript is not syntactically correct." >&2
fi

Bash script exiting prematurely when calling another script inside it

I have a bash script which calls another bash script, like so:
#!/bin/bash
echo "Hi"
./script-two.sh
echo "Hello!"
The problem that I have is that it never makes it to printing "Hello!"
I think this is because ./script-two.sh (Which I did not write) is somehow exiting or changing the shell. I have included this script at the end of this post.
Is there a way I can gurentee that my execution will continue after script-two.sh executes?
I have looked into using the trap command, but I don't fully understand its use properly.
Thanks,
Casey
Here is the contents of what would be script-two.sh
#!/bin/sh
# This file is part of the DITA Open Toolkit project hosted on
# Sourceforge.net. See the accompanying license.txt file for
# applicable licenses.
# (c) Copyright IBM Corp. 2006 All Rights Reserved.
export DITA_HOME=cwd
if [ "${DITA_HOME:+1}" != "1" ]; then
echo "DITA_HOME environment variable is empty or not set";
exit 127;
fi
echo $DITA_HOME
cd "$DITA_HOME"
# Get the absolute path of DITAOT's home directory
DITA_DIR="`pwd`"
echo $DITA_DIR
if [ -f "$DITA_DIR"/tools/ant/bin/ant ] && [ ! -x "$DITA_DIR"/tools/ant/bin/ant ]; then
chmod +x "$DITA_DIR"/tools/ant/bin/ant
fi
export ANT_OPTS="-Xmx512m $ANT_OPTS"
export ANT_OPTS="$ANT_OPTS -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl"
export ANT_HOME="$DITA_DIR"/tools/ant
export PATH="$DITA_DIR"/tools/ant/bin:"$PATH"
NEW_CLASSPATH="$DITA_DIR/lib:$DITA_DIR/lib/dost.jar:$DITA_DIR/lib/commons-codec-1.4.jar:$DITA_DIR/lib/resolver.jar:$DITA_DIR/lib/icu4j.jar"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9.jar:$DITA_DIR/lib/saxon/saxon9-dom.jar:$NEW_CLASSPATH"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9-dom4j.jar:$DITA_DIR/lib/saxon/saxon9-jdom.jar:$NEW_CLASSPATH"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9-s9api.jar:$DITA_DIR/lib/saxon/saxon9-sql.jar:$NEW_CLASSPATH"
NEW_CLASSPATH="$DITA_DIR/lib/saxon/saxon9-xom.jar:$DITA_DIR/lib/saxon/saxon9-xpath.jar:$DITA_DIR/lib/saxon/saxon9-xqj.jar:$NEW_CLASSPATH"
if test -n "$CLASSPATH"
then
export CLASSPATH="$NEW_CLASSPATH":"$CLASSPATH"
else
export CLASSPATH="$NEW_CLASSPATH"
fi
"$SHELL"
It looks like script-two.sh is setting up an ant build environment.
I think the author intended that it sets up the build environment, then you type your build commands in manually, then type exit to leave the build environment.
I say this because the bottom line of script-two.sh is:
"$SHELL"
which starts a new shell.
Try running your script, then type exit. I think you will see it print Hello! after you type exit.
I'm guessing you're trying to do something like:
#!/bin/bash
echo "Hi"
./script-two.sh
ant <some args>
To do that, what you really want to do is source it, by changing:
./script-two.sh
to
. script-two.sh
e.g.
#!/bin/bash
echo "Hi"
. script-two.sh
ant <some args>
But, you will need to edit script-two.sh and change:
"$SHELL"
to:
case $0 in *script-two.sh)
# executed, start a new shell with the new environment
"$SHELL"
;;
*)
# sourced, don't start a new shell
;;
esac
so that it only starts a shell if the script is being run like ./script-two.sh, but not if it is being sourced like . script-two.sh.
Or if you absolutely can't change script-two.sh, then you could do:
#!/bin/bash
echo "Hi"
. script-two.sh </dev/null
ant <some args>
which will trick "$SHELL" into exiting because it has no input.
Also
export DITA_HOME=cwd
doesn't seem right to me.
It should probably be
export DITA_HOME=$(pwd)
or
export DITA_HOME=`pwd`
(both are equivalent)
I had a similar problem today, up on digging I finally found the answer.
The script I was calling (from within my script) actually had an exit 0 in the end. Removing that fixed my issues.
Just leaving this here as someone may find it useful.
Well for starters, you can execute your bash script with the -x switch to see where it is failing:
bash -x script-one.sh
Secondly, if you call the second script like this:
#!/bin/bash
echo "Hi"
var=$(bash script-two.sh)
echo "Hello!"
It will continue, as long as script-two.sh exits cleanly. Again, you can run the -x script against that script find any problems.
And as Mikel mentioned, always make sure to have exit at the bottom of your scripts.

how to source a csh script in bash to set the environment [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 9 years ago.
Improve this question
We have Oracle running on Solaris, and the shell is by default csh. So the login script sets the oracle_home, oracle_sid in csh also. But I don't like csh and want to use bash to do my work. So how to source the csh login script in bash?
e.g, the following is what in the .cshrc file. And when use bash, I'd like use these variables. One way is to copy the variables again and use bash command, such as export ORACLE_SID=TEST. But doing so will require us to maintain two copies of the files. And when we change the database name, or upgrade the database, I need to maintain the bash login file separately. It's nice to just use something like
source .cshr in bash, but it doesn't work.
setenv ORACLE_SID TEST
setenv ORACLE_HOME /oracle/TEST/home/products/10204
setenv EPC_DISABLED TRUE
setenv MANPATH /usr/local/man:/usr/share/man
setenv EDITOR vi
setenv LD_LIBRARY_PATH $ORACLE_HOME/lib:/usr/sfw/lib/64
setenv NLS_LANG AMERICAN_AMERICA.UTF8
setenv NLS_DATE_FORMAT "DD-MON-RR"
In your ~/.bashrc (or the first of ~/.bash_profile, ~/.bash_login, and ~/.profile that exists) source this script using something like . ~/bin/sourcecsh:
#!/bin/bash
# This should be sourced rather than executed
while read cmd var val
do
if [[ $cmd == "setenv" ]]
then
eval "export $var=$val"
fi
done < ~/.cshrc
This version eliminates the evil eval:
#!/bin/bash
# This should be sourced rather than executed
# yes, it will be sourcing within sourcing - what so(u)rcery!
source /dev/stdin < \
<(
while read cmd var val
do
if [[ $cmd == "setenv" ]]
then
echo "export $var=$val"
fi
done < cshrc
)
Edit:
Without sourcing stdin:
while read cmd var val
do
if [[ $cmd == "setenv" ]]
then
declare -x "$var=$val"
fi
done < cshrc
How about just defining a function called setenv, like so
setenv() {
echo setting $1 to $2
export $1=$2
}
and then sourcing the .cshrc file.
When I do this in bash, I get
[dws#oxygen ual-read-only]$ source cshrc
setting ORACLE_SID to TEST
setting ORACLE_HOME to /oracle/TEST/home/products/10204
setting EPC_DISABLED to TRUE
setting MANPATH to /usr/local/man:/usr/share/man
setting EDITOR to vi
setting LD_LIBRARY_PATH to /oracle/TEST/home/products/10204/lib:/usr/sfw/lib/64
setting NLS_LANG to AMERICAN_AMERICA.UTF8
setting NLS_DATE_FORMAT to DD-MON-RR
[dws#oxygen ual-read-only]$ env | grep ORACLE
ORACLE_SID=TEST
ORACLE_HOME=/oracle/TEST/home/products/10204
I'm in the same boat. A coworker showed me the following:
Start off in bash, without the stuff in thwe environment:
bash> echo $$
12632
bash> echo $FOO
Here's the csh file that gets source'd:
bash> cat setup-env.csh
setenv FOO "some csh stuff"
echo FOO=$FOO in csh
Here's the command:
bash> csh -c 'source setup-env.csh;exec bash'
Look at the output from csh
FOO=some csh stuff in csh
And look at the output from the new bash shell
bash> echo $$
13487
bash> echo $FOO
some csh stuff
Now leave, and go back to the original bash shell
bash> exit
exit
bash> echo $$
12632
bash>
Note the echo $$ to see the process IDs, so that we can see they are different shell processes.
My coworker uses this enough that he puts it into an alias, like:
# make csh environment scripts useable (sourceable) from bash function
# from Phil McCoy, Wed Nov 9 2011
source_csh () {
exec csh -c " source $*; setenv ALREADY_SOURCED \"$ALREADY_SOURCED:$*:\"; exec bash"
}
# sounds like a great idea to do source_csh .cshrc or .login
# but naively done is infinitely recursive,
# since the exec'ed bash will run .bashrc
Unfortunately, I have found that I often needed not just environment variable setup, but also aliases setup, as in the modules package http://modules.sourceforge.net/.
I have been able to automate this "csh source script recipes" by using Perl Expect. But I have not been able to be as interactive as I would like, except for the above.
Only way I can think to do it would be to load csh and then call bash from that new shell. That way csh could parse that file, and then the bash that it spawns would inherit that environment as well.
In your bash .profile, you can do the following:
cat .cshrc | sed 's/setenv\s+(\S+)\s+(.*)$/set $1=$2; export $1/' > $HOME/.env_from_csh
source $HOME/.env_from_csh
For something that small, it's common to maintain two setup scripts, one for sh and sh-derived, shells, and one for csh and tcsh. As you mention, that does create the risk of the two scripts getting out of sync -- unless you generate one from the other, or generate both from a common source.
This places the burden on the maintainer of the setup script(s) rather than on each user who needs to use them.
There is a module available by which you can source same file where ever you want in perl script. And you will get all environment paths available in your csh file.
Source::Shell
Go through a little documentation for its usage.
Just having a "#!/bin/tcsh" or similar statement available at the start of the CSH script in conjunction with making the script executable solved the problem for me. I could directly call the CSH script from bash in this case.
As an example, I had to run tools.csh from a bash script called setup.sh. I did something like this in the bash script:
if [ -z \`head -1 tools.csh | grep '^#!'\` ];
then
TCSH=\`which tcsh\`;
echo "'#!'$TCSH" > tools.csh.temp;
cat tools.csh >> tools.csh.temp;
mv tools.csh.temp tools.csh;
fi;
chmod 755 tools.csh;
./tools.csh
# now I have all the setenv commands effective ...
Sourcing a csh file in bash will not work. You can change the default login shell from csh to bash if you are more confortable in bash. You could use chsh or as an admin to change it for you.
chsh -s /usr/local/bin/bash

Resources