为什么这个 while 循环在第一次迭代后退出?

为什么这个 while 循环在第一次迭代后退出?

我在 while 循环中尝试使用特定工具(esearch来自 NCBI 电子实用程序套件)时遇到了非常奇怪的情况。这是我的输入文件,一个字符串列表,每行一个:

$ cat transcripts.list 
NR_169596.1
NR_169595.1
NR_169594.1

我想esearch使用每个字符串作为参数来运行命令,所以我这样做:

$ while read -r line; do echo "Line: $line"; esearch -db nucleotide -query "$line"; done <  transcripts.list 
Line: NR_169596.1
<ENTREZ_DIRECT>
  <Db>nucleotide</Db>
  <WebEnv>MCID_61bb689d20b59b3e2e2d405d</WebEnv>
  <QueryKey>1</QueryKey>
  <Count>1</Count>
  <Step>1</Step>
</ENTREZ_DIRECT>

这是一个结果,而不是三个,正如您通过echo运行的单个结果所看到的那样。但是,如果我使用不好的做法 for环形:

$ for line in $(cat transcripts.list); do echo "Line: $line"; esearch -db nucleotide -query "$line"; done
Line: NR_169596.1
<ENTREZ_DIRECT>
  <Db>nucleotide</Db>
  <WebEnv>MCID_61bb68cabbe98560233344a7</WebEnv>
  <QueryKey>1</QueryKey>
  <Count>1</Count>
  <Step>1</Step>
</ENTREZ_DIRECT>
Line: NR_169595.1
<ENTREZ_DIRECT>
  <Db>nucleotide</Db>
  <WebEnv>MCID_61bb68cad05f5825d75e3ace</WebEnv>
  <QueryKey>1</QueryKey>
  <Count>1</Count>
  <Step>1</Step>
</ENTREZ_DIRECT>
Line: NR_169594.1
<ENTREZ_DIRECT>
  <Db>nucleotide</Db>
  <WebEnv>MCID_61bb68cb6bdec5435b5a41cb</WebEnv>
  <QueryKey>1</QueryKey>
  <Count>1</Count>
  <Step>1</Step>
</ENTREZ_DIRECT>

问题:这怎么可能?即使特定程序中存在某种错误esearch,也不应该影响循环,那么为什么 shell 在第一次迭代后退出呢?for工作又怎么会while失败呢?他们在这里做了什么不同的事情?


更多细节。

  1. 在 esearch 命令前面添加echo可使循环按预期运行,因此这必须与特定esearch命令相关(但这如何打破 shell 循环?):

    $ while read -r line; do echo esearch -db nucleotide -query "$line"; done <  transcripts.list 
    esearch -db nucleotide -query NR_169596.1
    esearch -db nucleotide -query NR_169595.1
    esearch -db nucleotide -query NR_169594.1
    
  2. 列表本身没有什么奇怪的,我可以用不同的列表重现它,并且没有隐藏字符:

    $ od -c transcripts.list 
    0000000   N   R   _   1   6   9   5   9   6   .   1  \n   N   R   _   1
    0000020   6   9   5   9   5   .   1  \n   N   R   _   1   6   9   5   9
    0000040   4   .   1  \n
    0000044
    
  3. 我在 bash 和 dash 中得到了相同的行为,所以它不能与 PIPEFAIL 或类似的东西相关。无论如何,该命令的退出状态都是 0:

     while read -r line; do esearch -db nucleotide -query "$line"; echo "EXIT: $?"; done <  transcripts.list 
    <ENTREZ_DIRECT>
      <Db>nucleotide</Db>
      <WebEnv>MCID_61bb69e71191d1185543b24a</WebEnv>
      <QueryKey>1</QueryKey>
      <Count>1</Count>
      <Step>1</Step>
    </ENTREZ_DIRECT>
    
  4. 这种情况发生在运行 Ubuntu、bash、版本 4.4.20(1)-release 的系统上。如果您想尝试一下,可以efetch使用 安装该工具。sudo apt install ncbi-entrez-direct

  5. 使用不同的语言在循环中按预期工作。例如,在perl

    $ perl -ne 'chomp;system("esearch -db nucleotide -query \"$_\"")' transcripts.list 
    <ENTREZ_DIRECT>
      <Db>nucleotide</Db>
      <WebEnv>MCID_61bb6c68d8f66e4bb03f00e8</WebEnv>
      <QueryKey>1</QueryKey>
      <Count>1</Count>
      <Step>1</Step>
    </ENTREZ_DIRECT>
    <ENTREZ_DIRECT>
      <Db>nucleotide</Db>
      <WebEnv>MCID_61bb6c69947ca95fce4d4f0f</WebEnv>
      <QueryKey>1</QueryKey>
      <Count>1</Count>
      <Step>1</Step>
    </ENTREZ_DIRECT>
    <ENTREZ_DIRECT>
      <Db>nucleotide</Db>
      <WebEnv>MCID_61bb6c6a85c14642940393f9</WebEnv>
      <QueryKey>1</QueryKey>
      <Count>1</Count>
      <Step>1</Step>
    </ENTREZ_DIRECT>
    

答案1

这可能是因为esearch耗尽了其标准输入;read并且esearch都在读取transcripts.list

要解决这个问题,请更改esearch的标准输入,例如 esearch < /dev/null

我正在逐行读取文件并运行 ssh 或 ffmpeg,只有第一行被处理!有关详细信息,请参阅 Bash 常见问题解答。

相关内容