Detect CRLF (^M) line terminators in shell script
Shell will complain 'bad interpreter' error for script which contains CRLF (^M) line terminators.
The error message likes 'bash: ./test.sh: /bin/bash^M: bad interpreter: No such file or directory'.
This generally caused by the script file was edited by a windows ( dos ) editor and saved with dos format.
How to check whether a shell script file contains CRLF? Either the below tricks can help you out.
1) Grep the hex code of CR.
The new line terminator for a text on Unix system is only LF. So, the once the file contains CR, it's not a compatible unix shell script.
The hex code of CR is 0x0D. The grep command is :
grep -c $'\x0D' test.sh
-c means print the total number of match character.
To be honestly, I do not understand the $ in this command either. :P I just found this black magic somewhere by Google.
--- update---
Quote from bash manual page:
Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. |
2) Find the hex code of CR by Perl Regular Expression.
The theory is the same to the above one. Just replace with Regular Expression. To be more precisely, Regular Expression match the whole CRLF in the end of each line.
perl -n -e 'print if /\x0d\x0a$/;' test.sh | wc -l
The hex code of LF is 0x0A. wc is to count all the matched lines.
3) Determin file's line teminator by file. This is my favorite one. :D
Command line tool file is used to check the file type of files. It also report the character set and line terminates of regular text file.
file -m /dev/null test.sh
-m /dev/null is a trick to force the file to treat shell script as a regular text file.
Detect file format is dos or unix
Detect file format with grep.
$ grep '^M' your-file-name
^M is Ctrl-V + Ctrl-M. If the grep returns any line, the file is in DOS format.
Detect file format with vim.
1) Open the file with vim.
2) Use the vim set command to show the file format.
:set ff?
The command returns fileformat=<dos/unix/mac> to indect current file format.