Прочитайте список файлов в unix и запустите команду

Я новичок в написании сценариев оболочки, и я весь день пытался понять, как выполнить команду «для». По сути, я пытаюсь сделать следующее:

У меня есть файл list.txt с кучей имен:

name1
name2
name3

для каждого имени в списке есть два разных файла, каждый с другим окончанием имени. Бывший:

name1_R1
name1_R2

Программа, которую я пытаюсь запустить, называется sickle. По сути, он берет два файла (которые соответствуют друг другу) и выполняет их анализ, поэтому мне требуется эта схема именования. Команда серпа выглядит следующим образом:

sickle pe -f input_file1.fastq -r input_file2.fastq -t sanger \

Если бы кто-то мог мне помочь, хотя бы просто рассказав, как заставить unix читать список файлов и обрабатывать каждую строку независимо, я думаю, что я мог бы пойти дальше. Я попробовал несколько вещей, но ни одна из них не сработала.


person user2647734    schedule 03.08.2013    source источник
comment
Добро пожаловать в Stack Overflow. Пожалуйста, скоро прочитайте страницу О. Командная строка вашего примера не имеет большого отношения к именам, которые вы указали в своем файле или сгенерировали из name1, что затрудняет догадку о том, что вы действительно хотите увидеть. Последовательность в написании вашего вопроса облегчает дать вам полезный ответ. Покажите точную командную строку, которую вы хотите сгенерировать для файловой базы name1. Каково значение обратной косой черты? Кроме того, хорошей идеей будет показать некоторые из того, что вы пробовали, а не просто абстрактно заявлять, что они не работают.   -  person Jonathan Leffler    schedule 03.08.2013
comment
См. также Перебор пар значений в bash.   -  person tripleee    schedule 13.04.2019


Ответы (3)


Есть несколько способов сделать это. Поскольку в файле данных имена указаны «по одному на строку», мы можем предположить, что в именах файлов нет новых строк.

for петля

for file in $(<list.txt)
do
    sickle pe -f "${file}_file1.fastq" -r "${file}_file2.fastq" -t sanger
done

while цикл с read

while read file
do
    sickle pe -f "${file}_file1.fastq" -r "${file}_file2.fastq" -t sanger
done < list.txt

Цикл for работает только в том случае, если в именах нет пробелов (или других пробельных символов, таких как табуляция). Цикл while чист до тех пор, пока у вас нет новых строк в именах, хотя использование while read -r file даст вам еще лучшую защиту от неожиданностей. Двойные кавычки вокруг имени файла в цикле for являются декоративными (но безвредными), поскольку имена файлов не могут содержать пробелы, но кавычки в цикле while предотвращают разделение имен файлов, содержащих пробелы, когда они не должны быть разделены. Часто бывает полезно заключать переменные в кавычки каждый раз, когда вы их используете, хотя строго это имеет значение только тогда, когда переменная может содержать пробелы, но вы не хотите, чтобы значение разделялось.

Мне пришлось угадать, какие имена следует передать команде sickle, поскольку ваш вопрос не ясен по этому поводу - я на 99% уверен, что угадал неправильно, но он соответствует различным суффиксам в вашей примерной команде, предполагающей базовое имя файла input. Я опустил обратную косую черту; это символ escape, и неясно, что вы там действительно хотите.

person Jonathan Leffler    schedule 03.08.2013
comment
работал как шарм. Большое спасибо! Да, я не хотел помещать имя в список, потому что думал, что так будет проще. - person user2647734; 03.08.2013
comment
С mywiki.wooledge.org/DontReadLinesWithFor цикл while действительно должен быть здесь первым предложением. - person tripleee; 30.06.2015

Используйте Bash For-Loop

Bash имеет очень разумный цикл for в качестве одной из циклических конструкций< /а>. Вы можете заменить команду echo ниже любой пользовательской командой, которую вы хотите. Например:

for file in name1 name2 name3; do
  echo "${file}_R1" "${file}_R2"
done

Идея состоит в том, что цикл присваивает каждому имени файла переменную file, а затем вы добавляете к ним суффиксы _R1 и _R2. Обратите внимание, что цитирование может быть важным и не причинит вреда, если в нем нет необходимости, поэтому вам следует использовать его как защитную меру программирования.

Используйте xargs для списков аргументов

Если вы хотите читать из файла вместо прямого использования цикла for, вы можете использовать Bash read встроенный, но xargs часто более переносим между оболочками. Например, в следующем примере используются флаги, доступные в версии xargs из GNU findutils для чтения аргументов из файла и добавления суффикса к каждому из них:

$ xargs --arg-file=list.txt --max-args=1 -I{} /bin/echo "{}_R1" "{}_R2"
name1_R1 name1_R2
name2_R1 name2_R2
name3_R1 name3_R2

Опять же, вы можете заменить «echo» на командную строку по вашему выбору.

person Todd A. Jacobs    schedule 03.08.2013
comment
Использование GNU xargs часто менее переносимо, чем просто использование Bash. Многие системы поставляются с Bash (даже если ваша оболочка не поддерживает), но гораздо меньше систем поставляются с утилитами GNU (например, Solaris, OS X, BSD,...) - person nneonneo; 03.08.2013
comment
Если в вашей версии xargs нет опции --arg-file, вы также можете просто перенаправить файл на STDIN: xargs -I{} /bin/echo "{}_R1" "{}_R2" < list.txt - person mschilli; 30.08.2013

Используйте цикл while с read:

while read fn; do
    <command> "${fn}_R1" "${fn}_R2"
done < list.txt
person nneonneo    schedule 03.08.2013
comment
Это имеет ту же проблему, что и ваша исходная версия с `cat fn`: имена файлов с пробелами не будут работать, потому что команда получит слишком много аргументов. Попробуйте вместо этого "${fn}_R1", "${fn}_R2". - person amalloy; 03.08.2013
comment
Спасибо, исправлено. Раньше я писал сценарии, не делая их безопасными для пространства, но недавно попытался изучить способы работы с пространством. Все еще приспосабливаюсь ;) - person nneonneo; 03.08.2013
comment
Вам даже не нужно указывать fn. Bash автоматически присваивает REPLY, чего обычно достаточно, если вы не присваиваете более одной переменной при каждом чтении. - person Todd A. Jacobs; 03.08.2013
comment
@CodeGnome: мне нравится прямо указывать имена моих переменных. Написание while read; do <command> $REPLY на мой вкус слишком "волшебно". - person nneonneo; 03.08.2013