Bash while循环:防止第三方命令从stdin读取

Bash while loop: Preventing third-party commands to read from stdin

假设一个输入 table (intable.csv) 在其第二列中包含 ID 号,以及一个新的输出 table (outlist.csv),其中输入文件- 延长一栏 - 将逐行写入。

echo -ne "foo,NC_045043\nbar,NC_045193\nbaz,n.a.\nqux,NC_045054\n" > intable.csv
echo -n "" > outtable.csv

进一步假设使用一个或多个第三方命令(此处:esearchefetchEntrez Direct 的两个部分)来检索每个 ID 号的附加信息。此附加信息将形成输出的第三列 table.

while IFS="" read -r line || [[ -n "$line" ]]
do
    echo -n "$line" >> outtable.csv
    NCNUM=$(echo "$line" | awk -F"," '{print }')
    if [[ $NCNUM == NC_* ]]
    then
        echo "$NCNUM"
        RECORD=$(esearch -db nucleotide -query "$NCNUM" | efetch -format gb)
        echo "$RECORD" | grep "^LOCUS" | awk '{print ","}' | \
          tr -d "\n" >> outtable.csv
    else
        echo ",n.a." >> outtable.csv
    fi
done < intable.csv

为什么 while 循环只遍历上述代码下的第一个输入 table 条目,而如果代码行以 开头,它会遍历所有输入 table 条目RECORDecho "$RECORD" 被注释掉了?我该如何纠正这种行为?

如果 esearch 从标准输入读取,就会发生这种情况。它将继承 while 循环的输入重定向,因此它将消耗输入文件的其余部分。

解决方案是将标准输入重定向到别处,例如/dev/null.

while IFS="" read -r line || [[ -n "$line" ]]
do
    echo -n "$line" >> outtable.csv
    NCNUM=$(echo "$line" | awk -F"," '{print }')
    if [[ $NCNUM == NC_* ]]
    then
        echo "$NCNUM"
        RECORD=$(esearch -db nucleotide -query "$NCNUM" </dev/null | efetch -format gb)
        echo "$RECORD" | grep "^LOCUS" | awk '{print ","}' | \
          tr -d "\n" >> outtable.csv
    else
        echo ",n.a." >> outtable.csv
    fi
done < intable.csv