Linux

Цикл по содержимому файла в Bash

Как мне в цикле перебрать каждую строку текстового файла с помощью 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

Решения для удаленного резервного копирования только для записи для предотвращения удаления резервной копии хакерами

Команды Linux. Шпаргалка
Linux

Команды Linux. Шпаргалка

Как просто удалить старые версии ядра Ubuntu в Linux Mint
Linux

Как просто удалить старые версии ядра Ubuntu в Linux Mint

Как пользоваться Wine: основы работы для начинающих и полезные советы
Linux

Как пользоваться Wine: основы работы для начинающих и полезные советы