2

Suppose I have the following shell script:

#!/bin/bash \n
echo "Hello World" \n

Running it gives

Hello world. 

Now suppose I have the following shell script

#!/bin/bash \r\n
echo "Hello world" \r\n

Running it gives the result:

bad interpreter: No such file or directory

To the newcomer - this doesn't really point to the cause of the issue (given that the cause is whitespace). What you really need is an error that tells you what the problem is.

My question is: How do I get bash to give a relevant error for a file with windows line-endings?

EDIT:

The context here is someone who looks at the file and doesn't see the line-endings - and has created this situation unintentionally. When asked about the difference between text files on unix and text files on windows they reply, "What do you mean? It's just plain text?" The question is directed at prompting the user to look at the root cause of the issue.

  • 1
    You can't (certainly not in any simple way, anyway). Bash never sees the file, the error is when trying to find which interpreter to use. Since that fails, the script is never given to bash at all. – terdon Jun 19 '16 at 0:47
  • 2
    bash: ./test.sh: /bin/bash^M: bad interpreter: No such file or directory is pretty clear if you look at the full message. You can obviously see the ^M there. – Julie Pelletier Jun 19 '16 at 0:47
  • You could easily set up a small conversion script such as: tr -d '\r' < $1 > $1.junk && cp $1.junk $1 && rm $1.junk. Note that the cp && rm instead of mv is to preserve permissions. – Julie Pelletier Jun 19 '16 at 0:52
  • 2
    Or just use the nearly ubiquitous dos2unix tool. – DopeGhoti Jun 19 '16 at 0:55
  • the newcomer quickly learns that bad interpreter: No such file or directory when the file looks OK must mean it's a DOS file and "doh! i forgot to strip carriage-returns. no problem, that's easily fixed." – cas Jun 19 '16 at 5:29
3

The problem is the error is happening before bash runs.

When you run a script starting with #! then the kernel looks at the rest of the line and runs that, with the filename as the first parameter. So when you have a file in DOS format the kernel will see /bin/bash^M and try to run that as the program. Which, of course, doesn't exist.

If you wanted to be a little insane you could create a program called /bin/bash^M ...

$ ls -lb /bin/bash?
-rwxr-xr-x 1 root root 61 Jun 18 22:41 /bin/bash\r

$ cat /bin/bash?
#!/bin/sh
echo Convert your program to Unix format!
exit 255

$ file foo
foo: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

$ cat -v foo
#!/bin/bash^M
echo hello^M

$ ./foo
Convert your program to Unix format!

$ dos2unix foo
dos2unix: converting file foo to Unix format ...

$ ./foo
hello

I'm not sure I'd recommend this, though!

Instead I'd recommend education and a diagnostic "run book" (e.g. the file command report CRLF line terminators).

  • That's awesome. – hawkeye Jun 19 '16 at 2:50
  • @StephenHarris Extending your excellent idea-- why not: add 2 lines to your /bin/bash^M: dos2unix ${@} to convert the file automatically and then ${@} to execute it? Additionally prompts and prints to confirm with the user... – Jedi Jun 19 '16 at 6:57
  • @Jedi This idea is insane enough as it is :-) Yes, we could try and rewrite files, but it may fail if ownership is wrong, for example. It gets complicated! Giving an error message helps teach people to "do it right", which will have long term benefits (eg when using a server without this safety net). I would not use the above outside of a classroom type setting :-) – Stephen Harris Jun 19 '16 at 12:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.