Как продолжить цикл 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
возвращается с успехом, а затем разрывает цикл.