我在 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
失败呢?他们在这里做了什么不同的事情?
更多细节。
在 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
列表本身没有什么奇怪的,我可以用不同的列表重现它,并且没有隐藏字符:
$ 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
我在 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>
这种情况发生在运行 Ubuntu、bash、版本 4.4.20(1)-release 的系统上。如果您想尝试一下,可以
efetch
使用 安装该工具。sudo apt install ncbi-entrez-direct
使用不同的语言在循环中按预期工作。例如,在
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 常见问题解答。