【问题标题】:sort tab delimited file排序制表符分隔文件
【发布时间】:2013-11-20 10:45:29
【问题描述】:

我正在尝试从 python 调用 unix 排序命令来对制表符分隔的文件进行排序,但我不能。当我用谷歌搜索它时,我发现在命令中添加 -t$'\t' 有效,当我尝试从 shell 排序时我也为我工作,但当我尝试从 python 时它不起作用。

这是我在脚本中尝试过的

tabdel="$'\t'"
sort_file_cmd="sort -t {1} -k2,2 -k6,6n {0}".format(file_to_be_sorted.name,tabdel)
print sort_file_cmd,shlex.split(sort_file_cmd)
subprocess.call(sort_file_cmd,stdout=sort_bt,shell=True)

print sort_file_cmd 打印这个

sort -t $'\t' -k2,2 -k6,6n human_vs_mouse.tab

从 shell 运行时效果很好,但从 python 脚本运行时会产生 sort: multi-character tab ‘$\t' 错误

我该如何克服这个问题?

样本数据

gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|10980 gi|58801268|ref|NP_001011737.1| olfactory receptor 1357 [Mus musculus]  3071921 1   307 1.90237e-150    1108.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|460 gi|22129025|ref|NP_667153.1| olfactory receptor 351 [Mus musculus]    302 10  915 2   303 5.70073e-105    806.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|4490 gi|33238878|ref|NP_666817.1| olfactory receptor 24 [Mus musculus]    308 1   921 1   307 9.58658e-105    805.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|458 gi|22129031|ref|NP_667152.1| olfactory receptor 353 [Mus musculus]    302 10  915 2   303 1.01585e-103    798.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|13639 gi|268837230|ref|NP_667200.2| olfactory receptor 1496 [Mus musculus]    3071921 3   309 1.50986e-99 771.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|13345 gi|283837936|ref|NP_666450.2| olfactory receptor 374 [Mus musculus] 310 1   930 1   310 4.18033e-99 768.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|455 gi|22129035|ref|NP_667150.1| olfactory receptor 354 [Mus musculus]    302 13  918 8   309 1.85488e-98 764.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|410 gi|22129071|ref|NP_667122.1| olfactory receptor 1377 [Mus musculus]   305 1   915 1   304 3.06622e-97 755.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|312 gi|53933206|ref|NP_001005569.1| olfactory receptor 366 [Mus musculus] 307 1   921 1   307 2.14345e-96 749.0  
gi|52317161|ref|NM_001004713.1| Homo sapiens olfactory receptor, family 1, subfamily I, member 1 (OR1I1), mRNA  gnl|BL_ORD_ID|4458 gi|58801284|ref|NP_001011748.1| olfactory receptor 867 [Mus musculus]    3091927 1   309 7.36974e-96 748.0   

【问题讨论】:

  • 另外,尝试使用 shlex import shlex shlex.split(sort_file_cmd) 分割命令
  • 请注意,像这样使用的shlex.split无用,因为它修改sort_file_cmd。另请注意,您不能使用shlex.split shell=True,因为shell=True 需要一个字符串,而shlex.split 返回一个字符串列表。请参阅我的答案以了解您应该如何使用它。
  • 样本数据中的空白都是制表符?因为 SO 搞砸了并将这些字符复制粘贴到文件中,所以我看不到 any 选项卡。

标签: python shell sorting


【解决方案1】:

您可以避免使用shell=True,只需使用list 代替字符串作为命令:

>>> subprocess.call(['sort', '-t', '\t', 'testing.txt'])
a       b
c       d
0

使用字符串列表代替构建单个流,每个字符串代表原始命令中的一个标记。在您的情况下,完整的“命令行”将是:

subprocess.call(['sort', '-t', '\t', '-k2,2', '-k6,6n', file_to_be_sorted.name])

请注意,此方法更安全,您应尽量避免使用shell=True。您必须仅在您想使用某些 shell 功能时使用shell=True,例如内置命令ifs、循环、管道(尽管这些可以构建使用subprocess.Popen...) 等。在您只想执行传递一些参数的命令的所有情况下,都可以避免使用 shell=True

您可以使用shlex.split 从命令字符串中获取字符串列表:

>>> cmdline = shlex.split("sort -t '\t' -k2,2 -k6,6n")
>>> cmdline
['sort', '-t', '\t', '-k2,2', '-k6,6n']
>>> cmdline.append(file_to_be_sorted.name)   # insert the last argument.

请注意,在这种情况下,您必须将 \t 括在原始字符串的单引号中。


如果您仍想使用shell=True,那么只需使用$'\t' 转义:

>>> subprocess.call("sort -t '\t' testing.txt", shell=True)
a       b
c       d
0

对我来说很好。

【讨论】:

  • 感谢您的回复 Bakuriu 但仍然抛出相同的错误排序:多字符制表符'$\\t'
  • @user2960593 我已经用另一种方法更新了我的答案来调用有效的子进程。我对这个错误感到困惑,因为使用原始字符串应该可以让它工作。 python 和 bash 对字符串的解释之间可能存在某种冲突。
  • Bakuriu 不起作用。虽然没有错误,但它没有按我的预期排序。我在问题中包含了示例数据集。请看一看。会不会是数据的原因?
  • @user2960593: shell=True 默认使用 /bin/sh 不理解 ANSI-C Quoting 因此最小的更改是添加参数 executable='bash'。但正如@Bakuriu 的回答所表明的,有更好的方法不需要shell=True
【解决方案2】:

$' ' 引用语法由 shell 解释。

你需要说:

tabdel=r'\t'

【讨论】:

  • 这不会引发任何错误,但 shlex split 表明它被解释为 -tt 因此输出未排序。
  • @user2960593 shlex.split 在您的代码中不存在。您能否发布您正在尝试的内容而不是发布其他内容?
  • 我很抱歉我在 Necrolyte2 的建议之后包含了 split.shlex。将更新我的问题。谢谢
  • @user2960593 我相信上面的建议应该适用于您的原始问题和修改后的问题。
  • r'\t' 被 shell (/bin/sh) 解释为 't',您可以使用 "'\t'" 代替(单引号内的文字制表符)。问题中的原始"$'\t'" 将与executable='bash' 参数一起使用。
猜你喜欢
  • 2010-11-05
  • 1970-01-01
  • 2013-08-24
  • 2013-06-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多