Как мне в цикле перебрать каждую строку текстового файла с помощью Bash?
Я использую следующий скрипт:
echo "Start!"
for p in (peptides.txt)
do
echo "${p}"
done
Я получаю такой вывод на экране:
Start!
./runPep.sh: line 3: синтаксическая ошибка – неожиданная лексема "('
./runPep.sh: line 3: "for p in (peptides.txt)'
Ответ 1
Один из способов сделать это:
while read p; do
echo "$p"
done <peptides.txt
Данный способ имеет побочные эффекты, заключающиеся в обрезке ведущих пробелов, интерпретации последовательностей обратной косой черты и пропуске последней строки, если в ней отсутствует завершающий перевод строки. Если это неприемлемо, можно сделать следующее:
while IFS="" read -r p || [ -n "$p" ]
do
printf '%s\n' "$p"
done < peptides.txt
В исключительных ситуациях, если содержимое считывается из стандартного ввода, можно открыть файл, используя другой дескриптор файла:
while read -u 10 p; do
...
done 10<peptides.txt
Здесь 10 - это просто произвольное число (отличное от 0, 1, 2).
Ответ 2
Вариант 1: используя цикл while - по одной строке за раз: перенаправление ввода:
#!/bin/bash
filename='peptides.txt'
echo Start
while read p; do
echo $p
done < $filename
Вариант 2: цикл while - открыть файл, прочитать из файлового дескриптора (в данном случае файлового дескриптора №4).
#!/bin/bash
filename='peptides.txt'
exec 4<$filename
echo Start
while read -u4 p ; do
echo $p
done
Ответ 3
Еще один способ выполнить данную операцию:
for word in $(cat peptides.txt); do echo $word; done
Этот формат позволяет поместить все это в одну командную строку. Изменяя часть «echo $word», вы можете выполнить несколько команд, разделенных точкой с запятой. В следующем примере содержимое файла используется в качестве аргументов двух других сценариев:
for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done
Или, если вы собираетесь использовать это как редактор потока (используя sed), можно выгрузить вывод в другой файл следующим образом:
for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt
Если у вас есть пробелы, которые вы не хотите разделять словами/строками, это становится немного сложнее, но та же команда по-прежнему работает следующим образом:
OLDIFS=$IFS; IFS=$'\n'; for line in $(cat peptides.txt); do cmd_a.sh $line; cmd_b.py $line; done > outfile.txt; IFS=$OLDIFS
Этот пример указывает оболочке разделять символы по строкам.
Ответ 4
Еще несколько возможных решений:
Чтение из файла с разделителями
# ':' является разделителем, и на каждой строке в файле имеются три поля
# IFS, установленный ниже, ограничен контекстом `read`, он не влияет на любой другой код
while IFS=: read -r field1 field2 field3; do
# обработка полей
# если строка содержит менее трех полей, то недостающие поля будут установлены в пустую строку
# если строка имеет более трех полей, `field3` получит все значения, включая третье поле плюс разделитель(и)
done < input.txt
Чтение вывода другой команды с использованием подстановки процесса
while read -r line; do
# обработка строки
done < <(command ...)
Этот подход лучше, чем command ... | while read -r line; do ...потому, что цикл while здесь выполняется в текущей оболочке, а не в подоболочке.
Чтение из ввода с разделителями NULL, например, find ... -print0
while read -r -d '' line; do
# использование второй строки 'read ... <<< "$line"', если нам нужно токенизировать строку
done < <(find /path/to/dir -print0)
Чтение из более чем одного файла за раз
while read -u 3 -r line1 && read -u 4 -r line2; do
# обработка строк
# обратите внимание, что цикл завершится, когда мы достигнем EOF в любом из файлов
done 3< input1.txt 4< input2.txt
Для совместимости с POSIX каждый вызов будет выглядеть примерно так read -r X <&3.
Чтение всего файла в массив (версии Bash до 4)
while read -r line; do
my_array+=("$line")
done < my_file
Если файл заканчивается неполной строкой (в конце отсутствует новая строка), то:
while read -r line || [[ $line ]]; do
my_array+=("$line")
done < my_file
Чтение всего файла в массив (версии Bash 4x и новее)
readarray -t my_array < my_file
или же
mapfile -t my_array < my_file
А потом:
for line in "${my_array[@]}"; do
# обработка строк
done
Linux