Как продолжить цикл while в bash, если программа напечатала определенное сообщение?

Я запускаю сценарий bash с использованием некоторого программного обеспечения, которое следует базовому шаблону ниже.

while read sample; do
    software ${sample} > output.txt
done <samples.txt

Для некоторых образцов печатается это сообщение: "Сайт Pf3D7_02_v3:274217 перекрывается с другим вариантом, пропуская..."

Это сообщение не останавливает работу программного обеспечения, но делает результаты ложными. Поэтому, если появляется сообщение, я хотел бы остановить программу и продолжить цикл while, переходя к следующему образцу. В файле samples.txt много образцов, поэтому я не могу сделать это вручную. Также может помочь способ обозначения образца сообщения. На самом деле я просто получаю много строк этого сообщения, не зная, для какого цикла это сообщение было задано.

Можно ли с этим помочь?

Fyi, программа, которую я использую, называется консенсусом bcftools. Дайте мне знать, если мне понадобится дополнительная информация.

Изменить: добавил "> output.txt" - понял, что слишком урезал его

Изменить 2: Вот полный фрагмент сценария с использованием предложения Чепнера ниже. Извините, это немного сложно:

mkfifo p
while IFS= read -r sample; do
    bcftools consensus --fasta-ref $HOME/Pf/MSP2_3D7_I_region_ref_noprimer.fasta --sample ${sample} --missing N $EPHEMERAL/bam/Pf_eph/MSP2_I_PfC_Final/Pf_60_public_Pf3D7_02_v3.final.normalised_bcf.vcf.gz --output ${sample}_MSP2_I_consensus_seq.fasta | tee p &
    grep -q -m 1 "The site Pf3D7_02_v3" p && kill $!
done <$HOME/Pf/Pf_git/BF_Mali_samples.txt
rm p

2 ответа

Я бы использовал именованный канал для вывода вывода по мере его создания.

mkfifo p
while IFS= read -r sample; do
    software "$sample" > p &
    tee < p output.txt | grep -q -m 1 "The site Pf3D7_02_v3:274217" p && kill $!
done < samples.txt
rm p

software будет записывать свой вывод в именованный канал в фоновом режиме, но блокируется до тех пор, пока tee начинает читать. tee будет читать из канала и записывать эти данные как в выходной файл, так и в grep. Еслиgrep находит совпадение, он выйдет и вызовет kill прекратить software (если он еще не завершился).

Если ваша версия grep не поддерживает -m вариант (распространенный, но нестандартный) можно использовать awk вместо.

awk '/The site Pf3D7_02:v3:274217/ { exit 1; }' p && kill $!
while read -u3 sample; do
    software ${sample} | 
    tee output.txt |
    { grep -q -m 1 "The site Pf3D7_02_v3:274217" && cat <&3 }
done 3< samples.txt

Входной файл перенаправляется на файловый дескриптор 3. Идея состоит в том, чтобы съесть все, что есть в третьем файловом дескрипторе, если обнаружен указанный текст. Поскольку мы перенаправляем вывод в файл, легкоtee output.txtа затем проверьте строку grep. Еслиgrep успешно, то мы cat <&3 съесть все с входа, так что следующий read -u3 не удастся.

Или:

while read sample; do
    if 
        software ${sample} | 
        tee output.txt |
        grep -q -m 1 "The site Pf3D7_02_v3:274217"
    then
        break;
    fi
done < samples.txt

Поскольку статус выхода конвейера - это последняя выполненная команда, мы можем просто проверить, grep возвращается с успехом, а затем разрывает цикл.

Другие вопросы по тегам