Why am I getting "line 1: $' :\r': command not found"?

You have Windows-style line endings.

The no-op command : is instead read as :<carriage return>, displayed as :\r or more fully as $':\r'.

Run dos2unix scriptname and you should be fine.


If you don't have dos2unix, the following should work almost anywhere (and I tested on MobaXterm on Windows):

vi -b filename

Then in vi, type:

:%s/\r$//
:x

You're good to go.


In vim, which is what you are using on Cygwin for vi, there are multiple ways of doing this. Another one involves the fileformat setting, which can take the values dos or unix. Either explicitly change it after loading the file with

set fileformat=unix
or explicitly force the file format when writing out the file with

:w +fileformat=unix

For more on this, see the many questions and answers here covering this subject, including:

  • Remove ^M character from log files
  • Why is vim creating files with DOS line endings?
  • How to add a carriage return before every newline?

This is due to the script having been saved by an editor that uses DOS line-endings (such as Notepad++, for example). You will have to remove these from your scripts.

To do this, either use dos2unix on the script file, or

$ tr -d '\r' <script >script.new && mv script.new script

(this will remove all carriage returns from anywhere in the script)


As for the code in the script:

:
iter=1
if [ -f iter.txt ]
   then rm ./iter.txt 
fi  

This should possibly look something like

iter=1
if [ -f "./$iter.txt" ]; then
   rm "./$iter.txt"
fi

This removes the file 1.txt from the current directory, if it exists. The : command does nothing (almost) and may be removed. The iter variable's value should be used as $iter, and be quoted. And then I'm possibly being more explicit than needs be by using ./ to say that the file needs to be found in the current directory.

If you're planning to turn this into a loop (here, deleting all files 1.txt, 2.txt, ..., 10.txt):

iter=1
while [ "$iter" -le 10 ]; then
    if [ -f "./$iter.txt" ]; then
        rm "./$iter.txt"
    fi
    iter=$(( iter + 1 ))
done

Or, if we feel sneaky/lazy,

rm -f {1..10}.txt

in shells that understands brace expansion.


Your scripts have the wrong line-endings. Windows uses CR+LF (\r\n), Unix uses LF (\n), and Classic MacOS uses CR (\r). You'll need to change the line-endings on all affected files, either with a text editor or a standalone tool like dos2unix.

FTP and version control systems like SVN tend to be able to convert the line endings appropriately, so you might want to look into those options for transferring files in the future.

If these files aren't being transferred, but just used on a single machine, then you'll want to find the settings for line endings in your preferred text editor. Most that are advertised as "for programmers" will have such an option.