最近整理电脑里的Python程序,有一个程序运行时出错:
$ ./absent.py
./absent.py: line 1: $'\357\273\277#!': command not found
./absent.py: line 4: $'\r': command not found
然后鼠标箭头变成了一个十字。如果如下:
$ python absent.py
用Python命令来执行是好的。这个文件的前5行如下:
#! /usr/bin/env python
# -*- encoding: utf-8 -*-
# 设置不同的文字屏保,2008年6月5日
import gtk
那个十字以前就碰到过,是用
./执行时程序被当成了Shell脚本,所以Python的
import gtk语句被当成ImageMagick的
import工具来执行了,那个十字形鼠标箭头是
import用来选取截图窗口的。
这个文件是我在原单位办公室的Windows电脑下创建的,所以马上意识到是换行符引起的。Linux下的换行符是
\n,而Windows下创建的文件换行符是
\r\n,所以第一行其实是这样的内容:
#! /usr/bin/env python\r\n
在Linux下,系统只把
\n识别为换行符,把
python和
\r连起来识别了。我创建了一个测试程序
dos.py:
#! /usr/bin/env python
# -*- encoding: utf-8 -*-
import this
然后在Shell下用
sed -i 's/$/^M/g' dos.py
把换行符转成Windows下的
\r\n。^
M是用Control-V和Control-M打出来的。这个文件执行出错:
$ ./dos.py
: No such file or directory
当然,用Python命令来解释是好的。上面的错误可以在Shell下用等同的命令复现:
$ /usr/bin/env python^M
: No such file or directory
如果真的有
python^M这个命令会呢?在
~/bin目录里创建到Python解释器的链接:
ln -s /usr/bin/python python^M
~/bin目录在
路径的前面,这样
python^M命令可以找到了。再执行一次就好了:
$ ./dos.py
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
......
其实不要用
env,直接在Shebang里面指定执行文件:
#! /home/tux/bin/python
# -*- encoding: utf-8 -*-
import this
出错会更直观:
$ ./dos.py
bash: ./dos.py: /home/tux/bin/python^M: bad interpreter: No such file or directory
在
~/bin里面创建名为
python^M的链接后,就又可以执行了。再回到开始的错误:
$ ./absent.py
./absent.py: line 1: $'\357\273\277#!': command not found
./absent.py: line 4: $'\r': command not found
这个错误和上面
dos.py的不同,这
'\357\273\277#!'是哪里来的呢?把
absent.py文件这样打开:
$ cat -e absent.py
M-oM-;M-?#! /usr/bin/env python^M$
# -*- encoding: utf-8 -*-^M$
# M-hM-.M->M-gM-=M-.M-dM-8M-^MM-eM-^PM-^LM-gM-^ZM-^DM-fM-^VM-^GM-eM--M-^WM-eM-1M-^OM-dM-?M-^]M-oM-<M-^L2008M-eM-9M-46M-fM-^\M-^H5M-fM-^WM-%^M$
^M$
import gtk^M$
原来在
#!之前还有几个字符,用
bvi打开:
00000000 EF BB BF 23 21 20 2F 75 73 72 2F 62 69 6E 2F 65 ...#! /usr/bin/e
00000010 6E 76 20 70 79 74 68 6F 6E 0D 0A 23 20 2D 2A 2D nv python..# -*-
它们是
0xEF,
0xBB和
0xBF。原来这个文件是用微软的Notepad创建的,在文件头被自动加上了UTF-8的
Byte Order Mark。用
cat -e absent.py打开时,在
#!前面显示的是
M-oM-;M-?,这是指
EE BB BF是把
'o',
';'和
'?'的高位设为1,可以如下验证:
>>> print ' '.join('%X' % (ord(b) + 128) for b in 'o;?')
EF BB BF
要解决问题,必须把前三个字节删除掉,并把换行转换为Unix格式的
\n才能用
./absent.py正确执行程序。