17

I use Cygwin on my laptop (DOS). I have a collection of scripts from my colleagues, and my own. I am not an IT person, not knowledgeable in Unix. I am following my colleagues' syntax and able to manage a few simple things.

The scripts worked well on my old laptop. I just changed laptop and installed Cygwin. When I run my scripts, they do not work. Here is one example of the error message I get:

line 1: $':\r': command not found
line 5: syntax error near unexpected token `$'\r''
line 5: `fi

Here are the top 5 lines of my script

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

Can someone please explain how I can get around this problem?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
TPham
  • 173

7 Answers7

38

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:

JdeBP
  • 68,745
Wildcard
  • 36,499
  • Just want to clarify, "iter=1" is my counter that will be used for the number of rounds of a math algorithm that my model will have to repeat later on beyond line 5. I just posted the top 5 lines to go with the error message. All comments and instruction are greatly appreciated !! – TPham Sep 08 '17 at 22:51
  • I just tried the suggested command "$ tr -d ..... " but there is something wrong with my laptop. It does not go back to "$" but the "> " appears on the screen instead. I have to use contrl C to get out. Then, I tested the script to see if the problem is fixed, but it is still there. Sorry, my knowledge in this field is very minimal ! I am trying to utilise my collection of scripts as they do help my work so much. Thank you everyone for being patient and helpful to me. – TPham Sep 08 '17 at 22:59
  • @TPham, see edit. If this works be sure to use the checkmark next to the answer to "accept" it. (Accept whichever answer best solved your problem.) https://unix.stackexchange.com/help/someone-answers – Wildcard Sep 08 '17 at 23:05
  • I use VIM as my text editor. I did try ":%s/\r//g" previously and then your suggestion":%s/\r$//" but I still get the same error message "Pattern not found: \r". I have no idea what is happening! Thanks for your instruction. – TPham Sep 08 '17 at 23:35
  • @TPham, did you use the -b flag when opening the file? It won't work without that. Read my answer carefully. – Wildcard Sep 08 '17 at 23:43
  • ah, my apologies ! I just repeat your instruction with -b, it works wonderfully. Thank you so much Wildcard !! You solved it !! I will slowly go through and sort out other scripts now. Have a wonderful day. – TPham Sep 09 '17 at 00:07
  • Since the questioner uses vim rather than vi, this answer would do better to mention vim's simple fileformat=unix setting, or even the +ff option to write. – JdeBP Sep 09 '17 at 07:12
  • @JdeBP, I think those are more complicated for this use case. But by all means, please write an answer describing those and their relative benefits. :) – Wildcard Sep 09 '17 at 07:16
  • 1
    Commands that are words are not really more complicated to a novice than a mysterious incantation that is almost wholly punctuation. This does not need a separate answer. It merely needs this answer to mention that vim can do this in two ways, one of which uses words. Or, better yet, to point to where this subordinate task has been answered over and over here in far more detail than any answer on this page, including https://unix.stackexchange.com/questions/88811/ just for starters. – JdeBP Sep 09 '17 at 07:23
  • @JdeBP you've convinced me. Would you mind editing it into this answer (with the link you mentioned)? Put it under a line break at the bottom if you would be so kind. – Wildcard Sep 09 '17 at 07:29
  • 2
    Note that vi -b, \r are vim extensions anyway. not POSIX, not in nvi, elvis, Solaris vi... – Stéphane Chazelas Sep 19 '17 at 10:21
10

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.

Kusalananda
  • 333,661
  • 3
    Notepad++ actually has the option to use Windows/Mac/Linux line breaks. You just need to go to the Edit menu and then EOL Conversion->Unix (LF). Or you could just double click in the bottom right corner where it says Windows (CR LF) and change it to Unix (LF) – jesse_b Sep 08 '17 at 22:35
  • Thank you everyone for your instruction. Would like to clarify: the "iter=1" is a counter that I use later on for my main objective, beyond line 5. – TPham Sep 08 '17 at 22:37
  • @TPham You're welcome. I was just bored and took your code and let my mind run impressionistic with it. – Kusalananda Sep 08 '17 at 22:43
  • Or rm -f [1-9].txt 10.txt. But that's not totally logically equivalent, as if there are no files 1-9 but there is a file literally called [1-9].txt then it will be deleted. :D – Wildcard Sep 08 '17 at 22:56
5

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.

Fox
  • 8,193
  • Thank you everyone for your helpful instruction. I just tried dos2unix but it seems I do not have it. Will search and try it again. – TPham Sep 08 '17 at 22:47
3

As a supplemental answer let me add a couple notes/tips...

First, for regular text files you can easily determine whether they have Unix or DOS line ending using the file command. For example:

$ file test.txt
test.txt: ASCII text, with CRLF line terminators
$ dos2unix test.txt
dos2unix: converting file test.txt to Unix format...
$ file test.txt
test.txt: ASCII text

Note my use of dos2unix. I highly recommend you install it. Depending on how you use Cygwin you may find you need to do this conversion often enough that the convenience is welcome. More importantly there is no chance of error like you get with the manual edits discussed here.

To install start the main Cygwin executable. That's the one with the name like setup-x86_64.exe or something along those lines. Make sure you see a screen like this:

enter image description here

Since you have already done the primary install you should be able to click Next all the way until you get the selection screen. Select Full in the dropdown and enter "dos2" in the search box and choose the tool as shown here:

enter image description here

Then click Next again and let the installation complete. That's it. Have fun. Cygwin, with the exception of this occasional inconvenience, is an awesome package.

B Layer
  • 5,171
  • Thank you very much for your instruction B Layer! This Stack Exchange group is so helpful. I really appreciate this support. – TPham Sep 12 '17 at 02:28
1

I use Notepad++ to edit my bash (.sh) scripts by connecting to the server by WinSCP
(To set up WinSCP editor to Notepad++ : https://winscp.net/eng/docs/ui_editor_preferences )

This is very practical for opening files from servers to edit/save instead of "Vim" editor.
When you open the file in Notepad++, double-click on the 7th column at the status bar at the bottom and select "Unix(LF)".

enter image description here

Also, you have to change the 8th one by Encoding -> Encode in UTF-8 in the top bar.

1

If not dos2unix, there is also 'flip'

$ flip -u yourfilename.txt

will flip it to using unix line endings.

Chai Ang
  • 148
0

You don't need to change the actual file's line encoding to have Cygwin's Bash happily work with Mac and Windows end-of-line encodings. There's an option you just need to flip on.

Just update your ~/.bash_profile so it contains

export SHELLOPTS
set -o igncr

See https://ptolemy.berkeley.edu/projects/chess/softdevel/faq/5.html

swdev
  • 176