Как мне перебрать каждую строку текстового файла с помощью 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 (geeko@buildhost) (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
Ответы:
Один из способов сделать это:
Как указано в комментариях, это имеет побочные эффекты от обрезания начальных пробелов, интерпретации последовательностей обратной косой черты и пропуска последней строки, если в ней отсутствует завершающий перевод строки. Если это проблемы, вы можете сделать:
В исключительных случаях, если тело цикла может читать из стандартного ввода , вы можете открыть файл, используя другой файловый дескриптор:
Здесь 10 - просто произвольное число (отличное от 0, 1, 2).
источник
while read p || [[ -n $p ]]; do ...
и однострочный вариант:
Эти параметры пропускают последнюю строку файла, если нет перевода строки в конце.
Вы можете избежать этого с помощью следующего:
источник
Вариант 1а: цикл «цикл»: по одной строке: перенаправление ввода
Вариант 1b: цикл «цикл»: по одной строке за раз:
открыть файл, прочитать из дескриптора файла (в данном случае дескриптор файла № 4).
источник
done < $filename
наdone 4<$filename
(что полезно, если вы хотите прочитать имя файла из параметра команды, и в этом случае вы можете просто заменить$filename
на$1
).tail -n +2 myfile.txt | grep 'somepattern' | cut -f3
, во время выполнения команд ssh внутри цикла (использует stdin); вариант 2 здесь представляется единственным выходом?Это не лучше, чем другие ответы, но это еще один способ выполнить работу в файле без пробелов (см. Комментарии). Я нахожу, что мне часто нужны однострочные, чтобы копаться в списках в текстовых файлах без дополнительного шага использования отдельных файлов скриптов.
Этот формат позволяет мне поместить все это в одну командную строку. Измените часть «echo $ word» на любую другую, и вы сможете вводить несколько команд, разделенных точками с запятой. В следующем примере содержимое файла используется в качестве аргументов для двух других сценариев, которые вы, возможно, написали.
Или, если вы намереваетесь использовать это как потоковый редактор (learn sed), вы можете вывести вывод в другой файл следующим образом.
Я использовал их, как написано выше, потому что я использовал текстовые файлы, где я создал их по одному слову в строке. (См. Комментарии) Если у вас есть пробелы, которые вы не хотите разбивать словами / строками, это становится немного уродливее, но та же команда по-прежнему работает следующим образом:
Это просто говорит оболочке разделить только на новые строки, а не пробелы, а затем возвращает среду обратно к тому, что было раньше. На этом этапе вы можете рассмотреть возможность помещения всего этого в сценарий оболочки, а не втискивать его в одну строку.
Удачи!
источник
for
делает входные токены / строки подчиненными расширениям оболочки, что обычно нежелательно; попробуйте это:for l in $(echo '* b c'); do echo "[$l]"; done
- как вы увидите,*
- хотя изначально он был заключен в кавычки - он расширяется до файлов в текущем каталоге.for
для перебора строк файла - плохая идея. Плюс аспект расширения, упомянутый @ mklement0 (даже если это возможно обойти, введя экранированные кавычки, что снова делает вещи более сложными и менее читаемыми).Еще несколько вещей, не охваченных другими ответами:
Чтение из файла с разделителями
Чтение из вывода другой команды с использованием подстановки процесса
Этот подход лучше, чем
command ... | while read -r line; do ...
потому, что цикл while выполняется в текущей оболочке, а не в подоболочке, как в случае последней. См. Соответствующий пост . Переменная, измененная внутри цикла while, не запоминается .Чтение из ввода с нулевым разделением, например
find ... -print0
Связанные чтения: BashFAQ / 020 - Как я могу найти и безопасно обрабатывать имена файлов, содержащие символы новой строки, пробелы или оба?
Чтение из более чем одного файла одновременно
На основе @ chepner в ответ здесь :
-u
это расширение bash. Для совместимости с POSIX каждый вызов будет выглядеть примерно такread -r X <&3
.Чтение всего файла в массив (версии Bash ранее до 4)
Если файл заканчивается неполной строкой (в конце отсутствует новая строка), то:
Чтение всего файла в массив (версии Bash 4x и выше)
или
А потом
Подробнее о встроенных функциях
read
иreadarray
командах оболочки - GNUПодробнее о
IFS
- ВикипедияПохожие сообщения:
источник
command < input_filename.txt
вас всегда можно сделатьinput_generating_command | command
илиcommand < <(input_generating_command)
Используйте цикл while, например так:
Ноты:
Если вы не установите
IFS
правильно, вы потеряете отступ.Вы почти всегда должны использовать опцию -r с read.
Не читать строки с
for
источник
-r
вариант?Note #2
это ссылка, где это подробно описано ...-u
опция не нужна. Вы говорите о другом примере-u
?Предположим, у вас есть этот файл:
Существует четыре элемента, которые изменят значение вывода файла, читаемого многими решениями Bash:
Если вы хотите, чтобы текстовый файл построчно включал пустые строки и завершающие строки без CR, вы должны использовать цикл while и иметь альтернативный тест для последней строки.
Вот методы, которые могут изменить файл (по сравнению с тем, что
cat
возвращает):1) Потерять последнюю строку, а также начальные и конечные пробелы:
(Если вы сделаете это
while IFS= read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
, вы сохраните начальные и конечные пробелы, но все равно потеряете последнюю строку, если она не заканчивается на CR)2) Использование процесса подстановки с
cat
волей читает весь файл за один раз и теряет значение отдельных строк:(Если вы удаляете
"
из$(cat /tmp/test.txt)
файла слово за словом, а не одним глотком. Также, вероятно, не то, что предназначено ...)Самый надежный и простой способ прочитать файл построчно и сохранить все пробелы:
Если вы хотите удалить ведущие и торговые пробелы, удалите
IFS=
часть:(Текстовый файл без завершения
\n
, хотя и довольно распространенный, считается поврежденным в POSIX. Если вы можете рассчитывать на конечный трейлинг, который\n
вам не нужен|| [[ -n $line ]]
вwhile
цикле.)Больше на BASH FAQ
источник
Если вы не хотите, чтобы ваше чтение прерывалось символом новой строки, используйте -
Затем запустите скрипт с именем файла в качестве параметра.
источник
источник
Вот мой реальный пример того, как зацикливать строки вывода другой программы, проверять подстроки, удалять двойные кавычки из переменной, использовать эту переменную вне цикла. Я предполагаю, что довольно многие задают эти вопросы рано или поздно.
Объявление переменной вне цикла, установка значения и использование его вне цикла требует выполнения синтаксиса <<< «$ (...)» . Приложение должно быть запущено в контексте текущей консоли. Кавычки вокруг команды сохраняют новые строки выходного потока.
Сопоставление цикла для подстрок затем считывает пару имя = значение , разделяет правую часть символа last = , удаляет первую кавычку, удаляет последнюю кавычку, у нас есть чистое значение, которое будет использоваться в другом месте.
источник
Это происходит довольно поздно, но с мыслью, что это может кому-то помочь, я добавляю ответ. Также это может быть не лучшим способом.
head
Команда может использоваться с-n
аргументом для чтения n строк из начала файла, а такжеtail
команда может использоваться для чтения снизу. Теперь, чтобы извлечь n-ю строку из файла, мы начинаем n строк , направляем данные к хвосту только на 1 строку из передаваемых данных.источник
sed
илиhead
+tail
является невероятно неэффективным, и, конечно , возникает вопрос , почему вы не просто использовать один из других решений здесь. Если вам нужно знать номер строки, добавьте счетчик вwhile read -r
цикл или используйте,nl -ba
чтобы добавить префикс номера строки в каждую строку перед циклом.Мне нравится использовать
xargs
вместоwhile
.xargs
мощный и дружественный к командной строкеcat peptides.txt | xargs -I % sh -c "echo %"
С помощью
xargs
вы также можете добавить детализацию с помощью-t
и проверку с помощью-p
источник
@Peter: Это может сработать для вас
Это вернет результат
источник