13

I installed Ubuntu bash on my windows machine, so I can test linux scripts away from work. I created a very simple script with basic "hello world" and a change directory (cd), but when executing it displays the hello world. It errors out on the cd to directory line.

Here is the error:

$ ./test.sh
hello world
zipping away
./test.sh: line 6: cd: $'/home/fjaffer/temp\r\r': No such file or directory
./test.sh: line 7: $'\r': command not found
ffr@DP-PC:~$

My script test.sh is below:

#!/bin/bash
echo "hello world"
echo "zipping away"
dir=/home/fjaffer/temp
cd $dir

Please advise? Thank you.

αғsнιη
  • 35,660
  • You'd normally want to use cd "$dir" instead of letting the shell word-split the expansion of "$dir". Surprised that didn't consume the \r characters. – Peter Cordes Sep 02 '18 at 16:23
  • 2
    @PeterCordes, the carriage return isn't contained in the default IFS (and it's not "IFS white space"), so it acts like any character, just invisible. – ilkkachu Sep 02 '18 at 16:57
  • 1
    Using cd in a script file and executing that script as a command (just specifying its name e.g. ./test.sh) won't do what you expect - the script runs in a subprocess, and the directory will be changed in that process, but not in your interactive shell. Using ". test.sh" uses the "." shell command to have your current interactive shell run the commands in the script, which will change the directory as you're expecting. (NOTE: this is how it works in Linux, things may be different in WSL.) – Randy Orrison Sep 03 '18 at 07:39

2 Answers2

18

It's because you have created your script in a windows machine, some \r (carriage return) has been added at the end of each line.

Remove them like this:

tr -d '\r' < test.sh > new-test.sh

Also quote the variable's value:

cd "$dir"

then run your script:

./new-test.sh

As a hint it's also better to use:

 cd ... || exit

in case of any failure.


Configure your editor so it uses Linux format for saving files (If it's capable of) or use an editor in bash like nano:

enter image description here

terdon
  • 100,812
Ravexina
  • 55,668
  • 25
  • 164
  • 183
  • 2
    dir=foo is basically safe, unless it contains literal whitespace. glob expansion doesn't happen on variable assignments. Where you really should use quoting is on cd "$dir". (Also, I just checked, and foo="abc"\r (carriage-return typed using control-v control-m in bash) still includes the CR in the value of foo, according to echo "$foo" | hexdump -C. So quoting doesn't protect variable definitions from trailing CRs on future edits, and also \r isn't a whitespace character for word-splitting.) – Peter Cordes Sep 02 '18 at 16:29
  • @PeterCordes The quoting was a general advice not relating to \r at all... but thank you for clarification :) – Ravexina Sep 02 '18 at 16:32
  • Yeah, I would normally quote variable definitions just because there's no reason not to. It's less necessary than in most other contexts, though, because glob expansion doesn't happen, only word splitting. But yeah, always quote unless you specifically want some kind of expansion somewhere. – Peter Cordes Sep 02 '18 at 16:34
  • 1
    @PeterCordes, word splitting doesn't happen in variable assignments. That is, if a contains foo bar, then b=$a also assigns foo bar to b. Of course if you do b="foo bar", you need the quotes, but that's just how the shell parses the input, and isn't the same as word splitting. – ilkkachu Sep 02 '18 at 16:59
  • It would even be better to have cd -- "$dir", in case the directory changed name to something like -L – user12205 Sep 03 '18 at 05:12
  • Thanks so much. I ended up changing the "line ending" setting in my editor and that removed the "/r" error. I am still not able to change directory, I only get the "hello world" output now. Please advise. – Femina Jaffer Sep 03 '18 at 13:16
  • @FeminaJaffer That's because the script execution happens in an other environment. to see that directory change you can use something like source script.sh or . ./script.sh – Ravexina Sep 03 '18 at 13:33
11

Another option is to using dos2unix command to convert the file to Unix type format.

Usage:

dos2unix your_file
αғsнιη
  • 35,660