linux - счетчиком - Зацикливание содержимого файла в Bash




linux mp3 tags (8)

@Peter: Это может сработать для вас -

echo "Start!";for p in $(cat ./pep); do
echo $p
done

Это вернет выходные данные,

Start!
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

Как выполнить итерацию каждой строки текстового файла с помощью Bash ?

С помощью этого скрипта:

echo "Start!"
for p in (peptides.txt)
do
    echo "${p}"
done

Я получаю этот вывод на экране:

Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'

(Позже я хочу сделать что-то более сложное с $p чем просто вывод на экран.)

Переменная среды SHELL (от env):

SHELL=/bin/bash

/bin/bash --version :

GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

выход cat /proc/version :

Linux version 2.6.18.2-34-default ([email protected]) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006

Файл peptides.txt содержит:

RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

Вот мой пример реальной жизни, как петлевые линии другого выхода программы, проверка подстрок, сброс двойных кавычек из переменной, использование этой переменной за пределами цикла. Наверное, многие задают эти вопросы рано или поздно.

##Parse FPS from first video stream, drop quotes from fps variable
## streams.stream.0.codec_type="video"
## streams.stream.0.r_frame_rate="24000/1001"
## streams.stream.0.avg_frame_rate="24000/1001"
FPS=unknown
while read -r line; do
  if [[ $FPS == "unknown" ]] && [[ $line == *".codec_type=\"video\""* ]]; then
    echo ParseFPS $line
    FPS=parse
  fi
  if [[ $FPS == "parse" ]] && [[ $line == *".r_frame_rate="* ]]; then
    echo ParseFPS $line
    FPS=${line##*=}
    FPS="${FPS%\"}"
    FPS="${FPS#\"}"
  fi
done <<< "$(ffprobe -v quiet -print_format flat -show_format -show_streams -i "$input")"
if [ "$FPS" == "unknown" ] || [ "$FPS" == "parse" ]; then 
  echo ParseFPS Unknown frame rate
fi
echo Found $FPS

Объявить переменную за пределами цикла, установить значение и использовать его за пределами цикла, необходимо сделать синтаксис <<< "$ (...)" . Приложение необходимо запускать в контексте текущей консоли. Котировки вокруг команды сохраняют новые строки выходного потока.

Loop match для подстрок затем читает пару name = value , разделяет правую часть last = character, бросает первую цитату, катит последнюю цитату, мы имеем чистую ценность, которая будет использоваться в другом месте.


Еще несколько вещей, на которые не распространяются другие ответы:

Чтение из файла с разделителями

# ':' is the delimiter here, and there are three fields on each line in the file
# IFS set below is restricted to the context of `read`, it doesn't affect any other code
while IFS=: read -r field1 field2 field3; do
  # process the fields
  # if the line has less than three fields, the missing fields will be set to an empty string
  # if the line has more than three fields, `field3` will get all the values, including the third field plus the delimiter(s)
done < input.txt

Чтение с вывода другой команды с использованием замещения процесса

while read -r line; do
  # process the line
done < <(command ...)

Этот подход лучше, чем command ... | while read -r line; do ... command ... | while read -r line; do ... command ... | while read -r line; do ... потому что цикл while здесь работает в текущей оболочке, а не в подоболочке, как в случае последней. См. Связанный пост . Измененная переменная внутри цикла while не запоминается .

Чтение из ввода с нулевым ограничением, например, find ... -print0

while read -r -d '' line; do
  # logic
  # use a second 'read ... <<< "$line"' if we need to tokenize the line
done < <(find /path/to/dir -print0)

Связанное чтение: BashFAQ / 020 - Как я могу найти и безопасно обрабатывать имена файлов, содержащие новые строки, пробелы или и то, и другое?

Чтение из более чем одного файла за раз

while read -u 3 -r line1 && read -u 4 -r line2; do
  # process the lines
  # note that the loop will end when we reach EOF on either of the files, because of the `&&`
done 3< input1.txt 4< input2.txt

Основываясь на @chepner's :

-u является расширением bash. Для совместимости с 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
  # process the lines
done

Похожие сообщения:

  • Создание массива из текстового файла в Bash
  • В чем разница между подходами к чтению файла с одной строкой?
  • Bash, хотя цикл чтения чрезвычайно медленный по сравнению с кошкой, почему?


Предположим, у вас есть этот файл:

$ cat /tmp/test.txt
Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR

Есть четыре элемента, которые изменят значение выходного файла, прочитанного многими решениями Bash:

  1. Пустая строка 4;
  2. Ведущие или конечные пробелы на двух строках;
  3. Поддержание значения отдельных строк (т. Е. Каждая строка - запись);
  4. Строка 6 не заканчивается CR.

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

Вот методы, которые могут изменить файл (по сравнению с тем, что возвращает cat ):

1) Потерять последнюю строку и передние и конечные пробелы:

$ while read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'

(Если вы делаете while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt вместо этого, вы сохраняете while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt пространства, но все равно теряете последнюю строку, если он не заканчивается CR)

2) Использование замены процесса с cat будет считывать весь файл за один глоток и теряет смысл отдельных строк:

$ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done
'Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR'

(Если вы удаляете " from $(cat /tmp/test.txt) вы читаете файл слово за словом, а не один глоток. Также, вероятно, не то, что предназначено ...)

Самый надежный и простой способ чтения файла по строке и сохранения всех интервалов:

$ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'    Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space    '
'Line 6 has no ending CR'

Если вы хотите разбить ведущее и торговое пространство, удалите IFS= part:

$ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
'Line 6 has no ending CR'

(Текстовый файл без завершающего \n , хотя и довольно распространенный, считается разбитым под POSIX. Если вы можете рассчитывать на завершающий \n вам не нужно || [[ -n $line ]] в цикле while.)

Больше в FAQ BASH


Это не лучше, чем другие ответы, но это еще один способ выполнить работу в файле без пробелов (см. Комментарии). Я нахожу, что мне часто нужны однострочники для прокрутки списков в текстовых файлах без дополнительного шага использования отдельных файлов сценариев.

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

Или, если вы намереваетесь использовать это как редактор потока (learn 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

Это просто говорит оболочке разделить только на новые строки, а не пробелы, а затем возвращает среду обратно к тому, что было ранее. На этом этапе вы можете захотеть включить все в сценарий оболочки, а не сжать все это в одну строку.

Удачи!


#!/bin/bash
#
# Change the file name from "test" to desired input file 
# (The comments in bash are prefixed with #'s)
for x in $(cat test.txt)
do
    echo $x
done

cat peptides.txt | while read line
do
   # do something with $line here
done




io