Как написать код для перебора нескольких файлов в Linux?

#linux #bash

#linux #bash

Вопрос:

У меня есть код, который я пытаюсь обновить из другого примера. Цель состоит в том, чтобы запустить plink, используя файлы: каждой хромосомы, идентификаторы snp и файл, содержащий только 1 идентификатор, который является индивидуальным идентификатором. Запуск этих файлов в plink в конечном итоге создает файл vcf для каждого индивидуума для данной хромосомы.

У меня есть 22 файла хромосом, 1 snp-файл (который всегда один и тот же) и 500 отдельных файлов. Для каждого отдельного пользователя я стремлюсь создать vcf для каждой хромосомы, поэтому у меня есть 22 * 500 (11000) файлов vcf в качестве выходных данных.

Выполняя это на данный момент, я попробовал скрипт bash с этим:

 ID=$SGE_TASK_ID
indiv=$SGE_TASK_ID

plink --bed chr${ID}.bed --bim chr${ID}.bim --fam chr${ID}.fam --extract snps.txt
--recode vcf-iid --out output${indiv}chr${ID}vcf --keep-fam individual${indiv}.txt
  

Это выполняется, однако оно выполняется только через 1 человека, предоставляя мне 22 файла vcf хромосом для этого одного человека, и на этом останавливается. Как мне запустить это для всех 500 пользователей, будет ли это с циклом for? Просматривая другие вопросы, я не смог найти тот, который соответствует моему вопросу и находится в Linux, буду признателен за любую помощь.

${indiv} было бы просто числом, поэтому выполняемый текстовый файл выглядит как individual1.txt и увеличивается на 500 человек (individual1.txt , individual2.txt , individual3.txt )

Ответ №1:

Предполагая, что ${indiv} не содержит пробелов,

 for indiv in $(<individuals.data); do
    plink [...] individual${indiv}.txt
done
  

В файле individuals.data будут указаны имена отдельных пользователей, разделенные пробелами или символами новой строки.

Если вы не уверены, что делает $(<...) оператор оболочки Bash, попробуйте это:

 for A in $(<individuals.data); do
    echo "[$A]"
done
  

Обратите внимание, что, как заметил @Kaz, если вы хотите, чтобы ваш скрипт работал также в оболочках, отличных от Bash, тогда вы могли бы написать $(cat ...) вместо $(<...)

Комментарии:

1. Нет необходимости делать это предположение (и это не будет единственным предположением, которое вам нужно сделать для использования for ). Смотрите Bash FAQ 001 .

2. @chepner Интересно. Я использую for для таких целей без инцидентов с 2004 года или около того, вероятно, сотни раз; но я, безусловно, готов к тому, чтобы меня научили лучшему способу работы. Однако я думаю , что вы ошибаетесь насчет пробелов.

3. Более точно $(< ...) является оператором GNU Bourne-Again Shell. Переносимый эквивалент $(cat ...) . В документации Bash утверждается, что $(< ...) это более быстрый эквивалент для $(cat ...) . Это совершенно глупо; Bash должен просто взять $(cat ...) синтаксис и перевести его в $(< ...) , а не заставлять программиста делать это в исходном коде. Поскольку cat это стандартная утилита, реализация оболочки может рассматривать ее как встроенную. Как только Bash будет исправлен для этого, $(< ...) синтаксис станет историческим ключом.

4. @Kaz Теперь ответ объединяет ваши наблюдения.

5. @tbh Если строка из файла содержит мета-символы типа * или ? , слова подлежат сопоставлению с шаблоном, поскольку замена команды не заключена в кавычки.