Linux系统如何处理文件中的CRLF?

时间:2019-07-01 19:12:38

标签: c linux compilation

我知道CR LF(\ r \ n)将被解释为两个字符,即“回车” +“换行”,但是当它例如源代码时,这将如何影响不同的程序?

  1. 作为要执行的bash脚本吗?
  2. 作为要编译的源代码?例如.c文件?

3 个答案:

答案 0 :(得分:3)

由于它是一系列空格字符,因此CRLF在C语言中会被忽略,但在Bash中不会被忽略:

如果bash脚本(#!/bin/bash)的第一行具有CRLF行终止符,则该脚本将无法运行。它将寻找文件/bin/bash\r,该文件不存在。

如果脚本的其他任何行上都有CRLF行终止符,则将找不到该行上的命令(因为bash正在寻找名为some_command\r的命令),或者将传递给{ {1}}在其最后一个参数的末尾。

答案 1 :(得分:1)

Shell脚本

默认情况下,shell不会将CR视为空白。

带有crlf67.sh标记的CR的源代码(^M):

#!/bin/sh^M
^M
echo "Hello^M
World!"^M

显式运行命令:

$ sh crlf67.sh
: command not found
Hello
World!
$ sh crlf67.sh 2>&1 | vis -r
crlf67.sh: line 2: ^M: command not found
Hello^M
World!^M
$

({vis命令是vis程序的扩展版本,从 Brian W Kernighan,Rob Pike The Unix Programming Environment(1983年11月)。它使非打印字符可见。)

如果使脚本可执行:

$  make crlf67
cat crlf67.sh >crlf67 
chmod a+x crlf67
$ crlf67
-bash: ./crlf67: /bin/sh^M: bad interpreter: No such file or directory
$

内核也不会将CR视为空白,并且无法找到命令。

C源代码

在C源代码中,正式地说,如果行尾为CRLF,则不能使用反斜杠在C中继续行,因为反斜杠后面的字符不是换行符(NL或LF);这是CR。在一行的最后一个反斜杠之后,某些编译器会忽略空格(至少是CR),GCC 9.1.0表示的是一个空格,但也包括较早的版本。它会在反斜杠后警告空格(除非您像我一样使用-Werror;否则会出错)。这不是标准规定的内容;但是,即使-pedantic也不会忽略错误的表示法而停止它。

源代码(crlf19.c),CR用^M标记,换行符用^J标记:

#include <stdio.h>^M^J
^M^J
int main(void)^M^J
{^M^J
    printf("Hello\   ^M^J
 world!\   ^M^J
\n");^M^J
    return 0;^M^J
}^M^J

GCC 9.1.0在macOS 10.14.5 Mojave上进行的编译:

$ gcc -O3 -g -std=c11 -Wall -Wextra -pedantic crlf19.c -o crlf19 
crlf19.c: In function ‘main’:
crlf19.c:5:18: warning: backslash and newline separated by space
    5 |     printf("Hello\
      |                   
crlf19.c:6:8: warning: backslash and newline separated by space
    6 |  world!\
      |         
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror crlf19.c -o crlf19 
crlf19.c: In function ‘main’:
crlf19.c:5:18: error: backslash and newline separated by space [-Werror]
    5 |     printf("Hello\
      |                   
crlf19.c:6:8: error: backslash and newline separated by space [-Werror]
    6 |  world!\
      |         
cc1: all warnings being treated as errors
$

此行为至少可以追溯到GCC 4.1.2 -该版本已在前Diluvian RHEL 5盒上进行了测试。

如果您在反斜杠后删除空格,仅留下CRLF行尾,那么GCC根本不会抱怨。

答案 2 :(得分:0)

这取决于正在处理文件的程序。我不相信有任何一般规则。

例如,我刚刚在原本为空的目录中创建了几个Shell脚本。其中一个名为some_command,文件名的最后一个字符为ASCII CR。

我可以通过将CR作为命令名的一部分从Shell脚本中调用该命令。外壳程序(sh,bash或ksh)不会将CR字符视为空格。

$ ls -l
total 16
-rwxr-xr-x 1 kst kst 26 Jul  1 16:46  crlf.bash
-rwxr-xr-x 1 kst kst 25 Jul  1 16:46  crlf.ksh
-rwxr-xr-x 1 kst kst 24 Jul  1 16:46  crlf.sh
-rwxr-xr-x 1 kst kst 21 Jul  1 16:49 'some_command'$'\r'
$ cat -v crlf.bash
#!/bin/bash
some_command^M
$ cat -v crlf.ksh
#!/bin/ksh
some_command^M
$ cat -v crlf.sh
#!/bin/sh
some_command^M
$ cat -v some_command
#!/bin/sh
echo hello
$ ./crlf.bash
Hello
$ ./crlf.ksh
Hello
$ ./crlf.sh
Hello
$

我正在使用的ls版本(GNU coreutils 8.28)具有特殊的语法,用于显示包含特殊字符的文件名。 cat -v将CR字符显示为^M