I have the following logic in the script Setup.sh.
#!/bin/bash
for ((i = 0 ; i < 5 ; i++))
do
echo "Welcome $i times."
done
When I run the script using the command ./Setup.sh, I get the error
./Setup.sh: line 3: syntax error near unexpected token `(('
./Setup.sh: line 3: `for ((i = 0 ; i < 5 ; i++))'
When I run the script using the command sh Setup.sh , I get the error
Setup.sh: syntax error at line 3: `(' unexpected
When I run the script logic in Execute BASH Shell Script Online using http://www.compileonline.com/execute_bash_online.php, it executes perfectly and prints the following.
Welcome 0 times.
Welcome 1 times.
Welcome 2 times.
Welcome 3 times.
Welcome 4 times.
Can someone help me understand why I get this error on Sun Solaris Unix machine?
When you run sh Setup.sh the Solaris /bin/sh is used to execute the script. The Solaris /bin/sh is not a POSIX shell and also does not understand the non-portable (()) syntax.
If you use #!/bin/bash it should work. If it doesn't, maybe your bash is very ancient. What does bash --version output?
The online demo uses bash 4.1.2(1)-release.
Please check which version of bash you have on the Solaris system.
bash --version
As far as I remember, the (( )) arithmetic notation was introduced recently. And it's a bashism, so it does not work with sh.
The website probably uses a new version of bash.
Related
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.
I have written the following code:
#!/bin/bash
#Simple array
array=(1 2 3 4 5)
echo ${array[*]}
And I am getting error:
array.sh: 3: array.sh: Syntax error: "(" unexpected
From what I came to know from Google, that this might be due to the fact that Ubuntu is now not taking "#!/bin/bash" by default... but then again I added the line but the error is still coming.
Also I have tried by executing bash array.sh but no luck! It prints blank.
My Ubuntu version is: Ubuntu 14.04
Given that script:
#!/bin/bash
#Simple array
array=(1 2 3 4 5)
echo ${array[*]}
and assuming:
It's in a file in your current directory named array.sh;
You've done chmod +x array.sh;
You have a sufficiently new version of bash installed in /bin/bash (you report that you have 4.3.8, which is certainly new enough); and
You execute it correctly
then that should work without any problem.
If you execute the script by typing
./array.sh
the system will pay attention to the #!/bin/bash line and execute the script using /bin/bash.
If you execute it by typing something like:
sh ./array.sh
then it will execute it using /bin/sh. On Ubuntu, /bin/sh is typically a symbolic link to /bin/dash, a Bourne-like shell that doesn't support arrays. That will give you exactly the error message that you report.
The shell used to execute a script is not affected by which shell you're currently using or by which shell is configured as your login shell in /etc/passwd or equivalent (unless you use the source or . command).
In your own answer, you say you fixed the problem by using chsh to change your default login shell to /bin/bash. That by itself should not have any effect. (And /bin/bash is the default login shell on Ubuntu anyway; had you changed it to something else previously?)
What must have happened is that you changed the command you use from sh ./array.sh to ./array.sh without realizing it.
Try running sh ./array.sh and see if you get the same error.
Instead of using sh to run the script,
try the following command:
bash ./array.sh
I solved the problem miraculously. In order to solve the issue, I found a link where it was described to be gone by using the following code. After executing them, the issue got resolved.
chsh -s /bin/bash adhikarisubir
grep ^adhikarisubir /etc/passwd
FYI, "adhikarisubir" is my username.
After executing these commands, bash array.sh produced the desired result.
I try to build the optiboot bootloader. This working with a few errors and I try to solve them. I guess optiboot is made to build on linux system.
So I installed https://sourceforge.net/projects/win-bash/files/shell-complete/latest/ and add its path to PATH variable.
But the bash/sh script was still comming back with "bad substitution"
The generated bash script look like the following. I added already the first line with #!/bin/bash but it gave not success.
#!/bin/bash
# 1 "baudcheck.c"
# 1 "C:\\Users\\trivalik\\Downloads\\arduino-1.8.0 \\hardware\\anet\\avr\\bootloaders\\atmega//"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "baudcheck.c"
# 24 "baudcheck.c"
bpsx=115200
bps=${bpsx/L/}
bps=${bps/U/}
fcpux=16000000L
fcpu=${fcpux/L/}
fcpu=${fcpu/U/}
echo $bpsx
echo $bps
when I execute this on operating system Windows 10 with "bash baudcheck.tmp.sh" I get:
115200
baudcheck.tmp.sh: ${bpsx/L/}: bad substitution
baudcheck.tmp.sh: ${bps/U/}: bad substitution
baudcheck.tmp.sh: ${fcpux/L/}: bad substitution
baudcheck.tmp.sh: ${fcpu/U/}: bad substitution
The main question is, what is on parameter substitiution on Windows different?
Or is it complete disabled?
All the bash tips here could me not help.
Edit:
Solution seems to be that the bash from win-bash is very very old.
The Version returns:
bash$ echo $BASH_VERSION
win-bash_0.8.5(0)
Instead I used now the bash from git for Windows https://git-for-windows.github.io/
this bash version is not the newest but higher:
$ echo $BASH_VERSION
4.3.42(5)-release
Does anybody know a higher bash Version for Windows?
I'm trying to run this script in my synology wit /bin/sh, it's all I have.
And while the script is working fine in normal /bin/bash environment, Synology is showing this error:
/volume2/myCustomPath/rotatingSnapshots.sh: line 22: syntax error: bad for loop variable
This is the code, the line which Synology is complaining about is the first one:
for (( i=$BIGGEST_NUMBER; i>=1; i-- ))
do
## Some code here
done
Any ideas? I can't find what is wrong.
/bin/sh refers to the POSIX shell. You're trying to use bash syntax in your script sp you should ideally be using the bash shell. This should work for you-
(Incidentally, you also don't need the $ in the loop).
#!/bin/bash
for (( i=BIGGEST_NUMBER; i>=1; i-- ))
do
## Some code here
done
I have a Ruby script that orchestrates a number of other scripts. One of the bash scripts pulls log data from a server, and a ruby script then parses them.
My bash script looks something like this:
#pullLogs.sh
for ((x = $2; x <= $3; x++)); do
# creates a subdirectory for each server number
rsync --progress -rvze ssh name#$ARCHIVE_SERVER:/path/to/log/$logDate.gz $x/
done
for ((x = $2; x <= $3; x++)); do
cd $x
for z in *.gz; do gunzip $z; done
cd ..
done
cd ..
What this script does is pulls logs from a given date, from specified servers. Usually there are ten servers, so the script will pull from server 1, then from server 2, etc etc.
This script works perfectly if I specify the desired date from the command line
./pullLogs.sh desired_date 1 10
successfully pulls all the logs from the desired date from all ten servers.
However, I want to pull all the logs from todays date to some past date, and parse each one. So I use this ruby script:
while upload_day != $DESIRED_DATE do
args = "#{year}#{month}#{day} 1 10"
`bash -c ./#{path_to_pullLogs_sh} #{args}`
`ruby #{name_of_followup_ruby_script}`
upload_day = upload_day.prev_day
end
The ruby script iterates through the correct days and calls the correct bash script (the one given above). However, after running the bash script, it produces an error:
./pullLogs.sh: line 15: ((: x = : syntax error: operand expected (error token is "= ")
./pullLogs.sh: line 21: ((: x = : syntax error: operand expected (error token is "= ")
So when I run it from the console, the loop variables 1 and 10 are good, but when I run it from the ruby script, it finds a problem with my syntax
How can make this work?
Drop the -c from your call to bash. This causes ./#{path_to_pullLogs_sh} to be used as the command to run, and the following arguments are passed as shell arguments starting with $0, not $1, meaning your script is short one argument.
`bash ./#{path_to_pullLogs_sh} #{args}`
(This works for the same reason as Z1MM32M4N's comment; it causes bash to treat ./pullLogs.sh as a script to run, rather than a string containing a snippet of shell code to execute.)