如何防止命令行参数被编码?

时间:2011-07-23 22:07:59

标签: python shell encoding character-encoding command-line-arguments

(问题解决了,请参阅更新)

由于编码问题,我有一些文件名不正确的文件。所以我想编写一个python脚本来处理它。但是,我遇到了一个奇怪的问题。

为了更好地说明,我将使用一个示例:文件名显示为¹þÀï·ÑÇ.mp3。 但是,以下结果不同:

# only one mp3 file is in this directory:
$ ls *mp3  | hexdump 
0000000 c2 b9 c3 be 41 cc 80 69 cc 88 41 cc 82 c2 b7 4e
0000010 cc 83 43 cc a7 2e 6d 70 33 0a                  
000001a

$ echo "¹þÀï·??Ç.mp3"  | hexdump 
0000000 c2 b9 c3 be c3 80 c3 af c3 82 c2 b7 c3 91 c3 87
0000010 2e 6d 70 33 0a                                 
0000015

基本上,第二个字符串(或字节)是我想要的,但在我的Python脚本中,命令行参数总是给我第一个字符串。我无法绕开。 我注意到这只发生在Mac OS X中。因此,我怀疑该参数是以某种方式由bash / system / python编码或处理的。 以下是我的工具列表:

  • Python:2.7.2
  • 操作系统:Mac OS X 10.6.7
  • Shell:GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)

更新:以下代码在我的Arch Linux 中运行良好,但在我的Mac OS X中遇到上述问题:

#!/usr/bin/env python

import sys 
import os
for name in sys.argv[1:]:
    try:
        # This line does the magic:
        new_name = name.decode('utf8').encode('latin-1').decode('gbk')
        new_name_utf8 = new_name.encode('utf8')
        if name != new_name_utf8:
            print "%s -> %s" % (name, new_name_utf8)
            os.rename(name, new_name)
    except:
        print "Ignoring %s" % name

在shell中,运行:

$ ./the_script *mp3 # Let bash pass the file name string

您可以为字符串¹þÀï·ÑÇ.mp3运行上述代码,并且应将其正确识别为哈里路亚.mp3。请注意,您必须具有UTF-8语言环境和支持Unicode的正确中文字体才能正确显示,或者检查以下图像:

Original filename

仅供参考:我的下载程序无法识别GBK编码的文件名,它被解释为unicode字符串,编码为UTF-8。原始文件中的非ascii字节被解释为Unicode的代码点,并使用UTF-8编码,这会导致问题。

Update2:Mac和Linux之间可移植的脚本现已上传here

2 个答案:

答案 0 :(得分:3)

问题是MacOS X的默认文件系统会将您提供给它的所有文件名更改为不使用预组合字符的异常规范化表单。 unicodedata Python模块允许在这些表单之间进行转换,例如:

import unicodedata
print len(unicodedata.normalize("NFD", u"\u00C7"))
print len(unicodedata.normalize("NFC", u"\u00C7"))

分别打印2和1。

答案 1 :(得分:0)

这样的事情:

J=1
for I in * ; do
    mv -i "$I" "$J"
    J=$((J+1))
done

这将迭代所有文件并将它们重命名为连续数字,这样就可以摆脱有问题的字符。