【问题标题】:Use of echo and system to run a software in C使用 echo 和 system 在 C 中运行软件
【发布时间】:2014-06-02 18:58:12
【问题描述】:

我正在尝试运行一个名为 BLASTP 的生物程序,它接收两个字符串(代码中的 fasta_GWIDD 和 fasta_UNIPROT)并比较它们。我遇到的问题是在代码中使用了 echo/system。谁能建议我错过了什么?

    for(i=0;i<index1;i++)
    {
        sprintf(fasta_GWIDD,">%s\\n%s\n",fasta_name1[i],fasta_seq1[i]);
        setenv("GwiddVar", fasta_GWIDD, 1) ;
        sprintf(fasta_UNIPROT,">%s\\n%s\n",fasta_name2[i],fasta_seq2[i]);
        setenv("UniprotVar", fasta_UNIPROT, 1) ;
        system("blastp -query <(echo -e $GwiddVar) -subject<(echo -e $UniprotVar)");
    }

错误是:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `blastp -query <(echo -e $GwiddVar) -subject<(echo -e $UniprotVar)'

【问题讨论】:

  • 首先让system 的参数语法被你的shell 接受。
  • 假设 $GwiddVar=">P10747_1\nMLRLLLALNLFPSIQVTGN" 和 $UniprotVar=">P10747_2\nMLRLLLALNLFPSIQVTGN"。从终端/命令行运行时,以下命令可以正常工作: blastp -query P10747_1\nMLRLLLALNLFPSIQVTGN") -subject P10747_2\nMLRLLLALNLFPSIQVTGN");

标签: c shell blast


【解决方案1】:

好像shell看不懂

<(echo -e $GwiddVar)

语法。请注意,system 命令可能使用不同于您习惯的 shell(例如 csh 而不是 bash,等等)。一切都在你的操作系统配置文件和配置文件的某个地方,但我猜不出你有什么。

顺便说一句。我认为您应该能够通过以下任一方式检查system() 命令正在使用哪个shell:

system("echo $SHELL")  // should simply write the path to current shell
system("ps -aux")      // look at it and find what is the parent of the PS

等等

考虑到这在某些 shell 上是正确的:

blastp -query <(echo -e $GwiddVar) -subject<(echo -e $UniprotVar)

上面引用的语法显然只是为了将变量作为输入传递。我认为你做得过火了。您正在使用echo -e $GwiddVar 来打印和捕获数据,这些数据已经在您手头的变量中。您是否尝试过以下简单的方法:

blastp -query $GwiddVar -subject $UniprotVar

我不知道您尝试使用哪个 shell,但考虑到 echo 获取了它的数据,那么它应该完全相同。

如果你担心空格,那么各种shell通常允许你使用引号:

blastp -query "$GwiddVar" -subject "$UniprotVar"

当然取决于shell。如果你的程序使用不喜欢引号的shell,那么你必须适应它。不是你的shell,而是system()使用的shell。

另一件事是使用system 非常粗糙。当您有难以正确转义的参数时,您应该使用其他函数 like execve 能够获取一组真正的原始直接字符串并将它们作为 ARGV 直接传递给进程。使用这些,您将不需要(也不应该)在要传递的字符串中添加任何引号或转义任何空格。

sprintf(fasta_GWIDD,">%s\\n%s\n",fasta_name1[i],fasta_seq1[i]);
sprintf(fasta_UNIPROT,">%s\\n%s\n",fasta_name2[i],fasta_seq2[i]);

char** args = .....; // allocate an array of char*[5], malloc, or whatever
args[0] = "blastp";
args[1] = "-query";
args[2] = fasta_GWIDD;
args[3] = "-subject";
args[4] = fasta_UNIPROT;

int errcode = execve(4, args, null);
if( errcode ) ... // check the error (if any) and react

但是!请注意, execve 来自 exec 系列,因此它会替换您当前的进程。这就是为什么我只写一个草图而不显示整个准备运行的代码。您可能需要在它之前fork(),然后等待外循环中的孩子。

所以,我先检查一下 shell 和语法;)

【讨论】:

  • 我的 shell 是 $echo $SHELL:/bin/bash 我尝试了以下但没有成功: system("blastp -query $GwiddVar -subject $UniprotVar); 错误:命令行参数错误:参数“subject”。文件不可访问:system("blastp -query \"$GwiddVar\" -subject \"$UniprotVar\"") 错误:命令行参数错误:参数“subject”。文件不可访问:
  • Argument "subject". File is not accessible 听起来像blastp将接收到的数据视为文件名。尽管如此,似乎没有echos 的两条线都有效,并且至少启动了blastp。根据 this page about BLAST+ 的说法,-query-subject 都需要一个 FILENAME,而不是直接字符串。你试过这种方法吗?将每个变量的内容写入某个单独的临时文件,然后传递 -query file1 -subject file2?
  • 是的,我已经尝试过使用文件名并且也成功了。但问题是我必须处理 10000 个或更多条目,并且打开/关闭文件需要太多时间。所以想用链接中提到的 Python 程序的字符串替换文件名:biostars.org/p/88563
  • 呼……所以这就是你所追求的。搜索“重定向标准输入”或“重定向标准输入”和“管道”。例如,here's how to do that。这不是你能找到的最好的文字,而是一个好的开始。总的来说,这完全是另一个故事,而不是简短的故事,我现在无法指导您,抱歉。你也可以在这里专门询问标准输入/标准输出重定向。这是一个很常见的问题,有很多资源和现成的答案。
【解决方案2】:

来自man 3 system

DESCRIPTION
    system()  executes a command specified in command by calling /bin/sh -c
    command, and returns after the command has been completed.

在许多系统上,/bin/sh 不是bash,即使是,它也是bash 的不同配置(如果bash 被调用为/bin/sh,它的操作通常会有所不同)。因此,您将bash 语法传递给不是bash 或不允许bash-isms 的完整集的shell...此外,-system 之后可能缺少一个空格令人困惑的事情...而且,我不完全确定环境变量在system() 字符串中扩展...

【讨论】:

  • 感谢您分享此信息。但是如何规避这个问题,因为我的shell确实是/bin/bash。
  • 我不确定你的代码还有什么作用,但这看起来像是一个尝试用 C 语言编写 shell 脚本的示例。为什么不直接编写一个 shell 脚本呢?类似for f in &lt;some list of files&gt;; do GwiddVar=&lt;something&gt;; UniprotVar=&lt;something&gt;; blastp -query .... ; done...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-06
  • 2018-11-10
  • 2015-07-24
  • 2012-12-03
  • 2016-04-01
  • 1970-01-01
相关资源
最近更新 更多