LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   bash script: Syntax error: redirection unexpected (https://www.linuxquestions.org/questions/linux-general-1/bash-script-syntax-error-redirection-unexpected-927865/)

make 02-06-2012 04:50 AM

bash script: Syntax error: redirection unexpected
 
This is probably an easy thing for you shell gurus but I'm banging my head to the wall with it. I updated Debian Lenny (5) to Squeeze (6). Now my script suddenly stopped working. Something has changed with bash.

Code:

#!/bin/bash

url=''

while grep -qv 'STOP$' <<<"$url"
do
  read -n1 next
  url="$url$next"
done

This part of the script is the problem. It is supposed to read characters into the variable $url until it gets a string "STOP" at the end of the URL address. It is used in our internal enterprise scripts.

It causes an error:
Code:

Syntax error: redirection unexpected
It refers to the line:
Code:

while grep -qv 'STOP$' <<<"$url
...so this line needs to be changed somehow.

everToulouse 02-06-2012 06:23 AM

hi,

sh is no longer a link to bash, but to dash which doesn't know about `<<<' that is not POSIX.

make 02-08-2012 12:30 AM

Quote:

Originally Posted by everToulouse (Post 4594974)
sh is no longer a link to bash, but to dash which doesn't know about `<<<' that is not POSIX.

So how do I get my scripts working again? Do I need to copy the old bash from the old Debian Lenny installation? Is there any other way?

Dark_Helmet 02-08-2012 01:01 AM

Well, the easiest solution would be to remove the change, right?

So, if /bin/sh was a symlink to /bin/bash in Lenny, but is now a symlink to /bin/dash, then you can point it back to /bin/bash. For instance, as root:
Code:

# cd /bin
# ln -sf bash sh

If you're not an administrator, then this is not a viable solution of course.

If your script is being invoked somewhere with "sh /path/to/script.bash" then it would probably be better to change that to "bash /path/to/script.bash" or better yet, because your script identifies the interpreter in the shebang line, make the script executable and invoke it directly: "/path/to/script.bash"

If there is some system utility invoking the script (e.g. cron) and it defaults to "sh /path/to/script.bash" you will need to change the symlink (as described above) or figure out how to configure that utility to launch your script with bash or launch the script directly (as described in the above paragraph)

Or, lastly, modify all your scripts to use POSIX-only syntax.

There may be other possible fixes, but those are what immediately come to mind.

Keep in mind, if you change the symlink, there could be a problem if any of the Debian maintainers included scripts that depend on dash features (just as you have scripts that depend on bash features). I think the chances of that would be minimal because, as far as I know, bash supports most (if not all) the POSIX syntax and/or feature set.

catkin 02-08-2012 01:44 AM

When run from the command line by ./test.sh (and so the shebang line is effective and it is run by bash), make's script does not give a syntax error but does hang. This when using bash version 4.1.7 (as determined by bash --version).

@make: what is the output of bash --version ?

Dark_Helmet 02-08-2012 02:06 AM

Interesting. I'm running Debian 6.0.3. It has bash 4.1.5 installed.

I pasted the script into a file, gave execute permissions, and ran it.

The script waited for input on stdin as expected until I typed "STOP" at which point it immediately ended.

So if it hangs on your end catkin, then there was a feature change in either 4.1.6 or 4.1.7.

make 02-08-2012 02:39 AM

Thank you for all the replies. Here's my bash version:
Code:

GNU bash, versio 4.1.5(1)-release (x86_64-pc-linux-gnu)
I just realized that I can run the scripts by typing "bash script-name.sh". This works without problems. How stupid of me... I assumed that it automatically took the "/bin/bash" specified in the beginning of the file, but it did not.

What would be the POSIX syntax of my script? Would it be better to change the scripts anyway?

Dark_Helmet 02-08-2012 03:24 AM

Quote:

Originally Posted by make
I just realized that I can run the scripts by typing "bash script-name.sh". This works without problems. How stupid of me... I assumed that it automatically took the "/bin/bash" specified in the beginning of the file, but it did not.

I agree with you. It should look at the interpreter specified in the shebang line. That is, after all, why it's there. But, somewhere there is some code that examines the file suffix and overrides (or ignores) the shebang line. In this case, your script has a ".sh" extension, and that code (wherever it is) decides to launch your script using /bin/sh.

On a minor rant here: it takes more effort to type "#!/bin/bash" than it does to give a filename a ".sh" extension. So, logically speaking, the greater effort should trump the lesser effort because, obviously, greater care/time went into the greater effort. It is dumb to ignore the shebang line when it's present. When I started using Linux, one of the "great differences" between Windows and Linux touted by the users was that Linux did not care about file extensions--Linux "figured it out." Ironic that the shell now seems to care more about file extensions than the shebang line by default.

Quote:

Originally Posted by make
What would be the POSIX syntax of my script? Would it be better to change the scripts anyway?

I'm on my way to bed. So, I'll give you some untested/unverified code that I think is POSIX and accomplishes the same task.
Code:

#!/bin/bash

url=''
while read inputLine ; do
  stopTest=`echo "${inputLine}" | grep 'STOP$'`
  if [ "${stopTest}x" = "x" ] ; then
    url="${url}${inputLine}"
  else
    exit 0
  fi
done


catkin 02-08-2012 03:52 AM

Quote:

Originally Posted by Dark_Helmet (Post 4596811)
The script waited for input on stdin as expected until I typed "STOP" at which point it immediately ended.

So if it hangs on your end catkin, then there was a feature change in either 4.1.6 or 4.1.7.

Sorry -- when I wrote "hangs" I meant it waited for user input. It behaves the same way that you describe.

catkin 02-08-2012 03:54 AM

Quote:

Originally Posted by make (Post 4596840)
I just realized that I can run the scripts by typing "bash script-name.sh". This works without problems.

How were you running it before?

make 02-08-2012 04:08 AM

Quote:

Originally Posted by catkin (Post 4596884)
How were you running it before?

./script-name.sh


Dark_Helmet: Your script works otherwise, but requires an enter press to stop. I couldn't immediately figure how to make it work like mine (so that it stops immediately upon finishing the word "STOP").

Of course, the most important thing is that I have my scripts now working. Just need to run them with a different command.

catkin 02-08-2012 07:49 AM

Quote:

Originally Posted by make (Post 4596898)
./script-name.sh

That should work, given the shebang line.

What is the output of /bin/bash --version ?

Dark_Helmet 02-08-2012 01:54 PM

Quote:

Originally Posted by make
Dark_Helmet: Your script works otherwise, but requires an enter press to stop. I couldn't immediately figure how to make it work like mine (so that it stops immediately upon finishing the word "STOP").

Yeah, I should have mentioned that the new version would require a newline for the script to process the input. I'm not sure there is a POSIX construct that would allow you access to the input character-by-character as they are entered.

As for the shebang-file extension conflict... I have not located the source, although I've been motivated to investigate some. I did encounter man update-binfmts which describes a kernel-based file extension-interpreter registry. I ran "/usr/sbin/update-binfmts --display" expecting to see an association between a "sh" extension and "/bin/sh" but there was none. The only listings on my system were for python, wine, java, and cli/mono.

Other people have encountered the file extension problem as well. I had helped another user with an expect script. Even with the correct shebang line pointing to the local installation of expect, his script failed because the filename has a "sh" extension and was being invoked with /bin/sh. Only when he renamed it with a "exp" extension (or something similar) did the correct interpreter get launched.

Anyway, if you don't want to bother with it, use a file extension of "bash" or remove the extension entirely.

Or... wait till someone tracks down the source and posts here :)

make 02-08-2012 02:26 PM

Quote:

Originally Posted by catkin (Post 4597013)
What is the output of /bin/bash --version ?

Code:

GNU bash, versio 4.1.5(1)-release (x86_64-pc-linux-gnu)
As long as bash doesn't get any updates that would make my scripts obsolete (strictly POSIX-only), the problem can be considered as solved. So in the end this thread was helpful. :) The solution was just simpler than I expected. Running the scripts with "bash script-name" is fine with me, regardless of the extensions.

Funny how I never paid attention how these shells were symlinked. Been using Debian for 10 years. I always assumed they were separate binaries and never took a closer look inside /bin. Learning new things every day. :)


All times are GMT -5. The time now is 01:07 AM.