Читайте файл построчно, присваивая значение переменной

У меня есть следующий файл .txt:

Marco
Paolo
Antonio

Я хочу читать это построчно, и для каждой строки я хочу присвоить строковое значение .txt переменной. Предположим, моя переменная$nameпоток:

Read first line from file Assign $name = "Marco" Do some tasks with $name Read second line from file Assign $name = "Paolo"
 andand18 июл. 2016 г., 16:33
Возможный дубликатLooping through the content of a file in Bash?
 Egor Hans12 нояб. 2017 г., 17:11
Можно ли как-то объединить эти вопросы? У обоих есть действительно хорошие ответы, в которых освещаются различные аспекты проблемы, плохие ответы содержат подробные объяснения в комментариях о том, что в них плохого, и на данный момент вы не можете получить полный обзор того, что следует рассмотреть, из ответы на один вопрос из пары. Было бы полезно иметь все это в одном месте, а не на 2 страницы.

Ответы на вопрос(10)

Использование следующего шаблона Bash позволит вам читать по одному значению за раз из файла и обрабатывать его.

while read name; do
    # Do what you want to $name
done < filename
 29 июн. 2016 г., 01:42
@CalculusKnight, это только «сработало» потому что вы не использовали достаточно интересные данные для тестирования. Попробуйте использовать контент с обратной косой чертой или строку, содержащую только*.
 14 дек. 2016 г., 17:06
@Matthias, ... и этоespecially Здесь верно, поскольку примеры кода, показанные в StackOverflow, предназначены для использования в качестве обучающих инструментов, чтобы люди могли повторно использовать шаблоны в своей работе!
 07 июн. 2016 г., 13:36
Кроме как хочешьread -rи вам нужно процитировать"$name".
 14 дек. 2016 г., 16:59
@Matthias, предположения, которые в конечном итоге оказываются ложными, являются одним из крупнейших источников ошибок, как влияющих на безопасность, так и других. Самое большое событие потери данных, которое я когда-либо видел, было связано со сценарием, который, как предполагалось, «буквально никогда не возникнет». - переполнение буфера, сбрасывающее случайную память в буфер, используемый для именования файлов, в результате чего сценарий, делающий предположения о том, какие имена могут когда-либо встречаться, имеет оченьvery неудачное поведение.
 03 дек. 2015 г., 00:17
как однострочник: пока читаешь имя; сделать эхо $ {имя}; сделано & lt; имя файла

Для правильной обработки ошибок:

#!/bin/bash

set -Ee    
trap "echo error" EXIT    
test -e ${FILENAME} || exit
while read -r line
do
    echo ${line}
done < ${FILENAME}
 10 апр. 2018 г., 20:28
Не могли бы вы добавить объяснение?
 29 нояб. 2018 г., 23:22
... а также, из-за отсутствия цитирования, строки мунгов, которые содержат символы подстановки - как описано вBashPitfalls #14.
 19 апр. 2018 г., 09:15
К сожалению, он пропускает последнюю строку в файле.

Следующее просто распечатает содержимое файла:

cat $Path/FileName.txt

while read line;
do
echo $line     
done

Я призываю вас использовать-r флаг дляread что означает:

-r  Do not treat a backslash character in any special way. Consider each
    backslash to be part of the input line.

Я цитируюman 1 read.

Другое дело - взять имя файла в качестве аргумента.

Вот обновленный код:

#!/usr/bin/bash
filename="$1"
while read -r line; do
    name="$line"
    echo "Name read from file - $name"
done < "$filename"
 23 февр. 2016 г., 22:42
@ Томас, а что происходит с пробелами посередине? Подсказка: нежелательная попытка выполнения команды.
 21 сент. 2014 г., 15:25
Обрезает начальные и конечные пробелы от линии
 14 дек. 2016 г., 18:28
Тем не менее, этоdoes все еще нужно изменить, чтобы установитьIFS= дляread для предотвращения обрезки пробелов.
 30 июн. 2016 г., 16:15
Это сработало для меня, в отличие от принятого ответа.
 14 дек. 2016 г., 18:25
@TranslucentCloud, если это сработало, а принятый ответ не получился, я подозреваю, что ваша оболочка былаshнеbash; расширенная команда тестирования, используемая в|| [[ -n "$line" ]] синтаксис в принятом ответе - это башизм. Тем не менее, этот синтаксис на самом деле имеет соответствующее значение: он заставляет цикл продолжаться до последней строки во входном файле, даже если он не имеет новой строки. Если вы хотите сделать это в POSIX-совместимом виде, вам нужно|| [ -n "$line" ], с помощью[ скорее, чем[[.
#! /bin/bash
cat filename | while read LINE; do
    echo $LINE
done
 08 апр. 2016 г., 13:42
Бесполезное использование кошки, не так ли?
 07 июн. 2016 г., 13:35
И цитата не работает; и вы не должны использовать имена переменных в верхнем регистре, потому что они зарезервированы для системного использования.
 10 сент. 2017 г., 21:18
Другая проблема состоит в том, что канал открывает новый подоболочек, то есть все переменные, установленные внутри цикла, не могут быть прочитаны после завершения цикла.
 29 июн. 2016 г., 01:46
@AntonioViniciusMenezesMedei, ... более того, я видел, как люди терпят финансовые убытки, потому что они полагали, что эти предостережения никогда не будут иметь для них значения; не выучил хорошие практики; а затем следовал привычкам, к которым они привыкли при написании сценариев, управляющих резервным копированием критических данных выставления счетов. Важно научиться правильно делать вещи.
 16 февр. 2016 г., 14:32
Ничего не имею против других ответов, может быть, они более изощренные, но я одобряю этот ответ, потому что он прост, читабелен и достаточен для того, что мне нужно. Обратите внимание, что для того, чтобы он работал, текстовый файл, который нужно прочитать, должен заканчиваться пустой строкой (то есть нужно нажатьEnter после последней строки), в противном случае последняя строка будет игнорироваться. По крайней мере, так случилось со мной.

Если вам нужно обработать как входной файл, так и пользовательский ввод (или что-либо еще из stdin), используйте следующее решение:

#!/bin/bash
exec 3<"$1"
while IFS='' read -r -u 3 line || [[ -n "$line" ]]; do
    read -p "> $line (Press Enter to continue)"
done

На основепринятый ответ и наРуководство по перенаправлению bash-хакеров.

Здесь мы открываем дескриптор файла 3 для файла, переданного в качестве аргумента скрипта, и сообщаемread использовать этот дескриптор в качестве ввода (-u 3). Таким образом, мы оставляем дескриптор ввода по умолчанию (0), прикрепленный к терминалу или другому источнику ввода, способный считывать ввод данных пользователем.

Многие люди опубликовали решение, которое было чрезмерно оптимизировано. Я не думаю, что это неправильно, но я скромно думаю, что было бы желательно менее оптимизированное решение, которое позволило бы всем легко понять, как это работает. Вот мое предложение:

#!/bin/bash
#
# This program reads lines from a file.
#

end_of_file=0
while [[ $end_of_file == 0 ]]; do
  read -r line
  # the last exit status is the 
  # flag of the end of file
  end_of_file=$?
  echo $line
done < "$1"

Я читаю вопрос как:

& quot; если я хочу прочитать файл с помощью ожидайте, как я должен делать? Я хочу сделать это, потому что когда я писал «выполняю некоторые задачи с $ name», я имел в виду, что мои задачи - ожидаемые команды. & Quot;

Прочитайте файл изнутри, ожидайте самого себя:

yourExpectScript:

#!/usr/bin/expect
# Pass in filename from command line

set filename [ lindex $argv 0 ]

# Assumption: file in the same directory

set inFile [ open $filename r ]

while { ! [ eof $inFile ] } {

    set line [ gets $inFile ]

    # You could set name directly.

    set name $line

    # Do other expect stuff with $name ...

    puts " Name: $name"
}

close $inFile

Тогда назовите это как:

yourExpectScript file_with_names.txt
 15 июн. 2016 г., 14:16
Это не похоже на bash.
 12 нояб. 2017 г., 17:59
Похоже, кто-то никогда не слышал о сценариях не-TCL раньше. Однако, если я не ошибаюсь, TCL может быть вызван из bash и наоборот, так что этот ответ действительно сработает.
 15 мая 2018 г., 23:43
На самом деле это интересный ответ, хотя он и не актуален.
 14 дек. 2016 г., 18:23
Действительно - это TCL (язык, на которомexpect расширяется), что очень сильно не bash.
Решение Вопроса

Следующее (сохранить какrr.sh) читает файл, передаваемый в качестве аргумента построчно:

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
    echo "Text read from file: $line"
done < "$1"

Объяснение:

IFS='' (or IFS=) prevents leading/trailing whitespace from being trimmed. -r prevents backslash escapes from being interpreted. || [[ -n $line ]] prevents the last line from being ignored if it doesn't end with a \n (since read returns a non-zero exit code when it encounters EOF).

Запустите скрипт следующим образом:

chmod +x rr.sh
./rr.sh filename.txt

....

 14 дек. 2016 г., 17:11
@ Ondra & # x17D; я & ka; это вызваноffmpeg потребляя стандартный добавлять</dev/null на вашffmpeg линии, и он не сможет или использует альтернативный FD для цикла. Это «альтернативный FD» Подход выглядитwhile IFS='' read -r line <&3 || [[ -n "$line" ]]; do ...; done 3<"$1".
 16 янв. 2014 г., 17:25
Есть предостережение с этим методом. Если что-то внутри цикла while является интерактивным (например, читает из stdin), то оно будет принимать входные данные от $ 1. Вам не будет предоставлена возможность вводить данные вручную.
 03 дек. 2015 г., 00:20
как однострочник: тогда как IFS = '' читать строку -r || [[-n & quot; $ line & quot; ]]; сделать эхо "$ line"; сделано & lt; имя файла
 21 мая 2017 г., 23:32
grumble Re: консультирование.sh расширение. Исполняемые файлы в UNIX, как правило, вообще не имеют расширений (вы не запускаетеls.elf) и имея bash shebang (и инструменты только для bash, такие как[[ ]]) и расширение, подразумевающее совместимость с POSIX sh, является внутренне противоречивым.
 20 мая 2014 г., 23:22
Примечательно - некоторые команды нарушают (как, например, они нарушают цикл) это. Например,ssh без-n Флаг эффективно заставит вас выйти из цикла. Вероятно, на это есть веская причина, но мне потребовалось некоторое время, чтобы понять, что приводило к сбою моего кода, прежде чем я это обнаружил.

Использование:

filename=$1
IFS=

Если вы установилиIFS иначе вы получите странные результаты.

\n' for next in `cat $filename`; do echo "$next read from $filename" done exit 0

Если вы установилиIFS иначе вы получите странные результаты.

 10 дек. 2016 г., 15:40
Это хороший метод, я рекомендую его для более сложных скриптов. Смотрите мой комментарий наread ответ.
 20 мая 2014 г., 14:28
This is a horrible method, Пожалуйста, не используйте его, если вы не хотите, чтобы у вас возникали проблемы с глобализацией, которые возникнут до того, как вы это поймете!
 17 мар. 2015 г., 15:56
Это не ужасно, без перерыва в исполнении.
 14 окт. 2015 г., 18:44
@MUYBelgium вы пробовали с файлом, который содержит один* на линии? Тем не мение,this is an antipattern. Don't read lines with for.
 14 дек. 2016 г., 17:14
@ Ondra & # x17D; я & ka,read подходthe best-practices approach by community consensus, Предостережение, которое вы упоминаете в своем комментарии, применимо, когда ваш цикл запускает команды (такие какffmpeg) которые читаются из stdin, тривиально решаются с использованием не-stdin FD для цикла или перенаправления таких команд & apos; вход. В отличие от этого, работая над ошибкой в вашейforПодход -loop означает внесение (и затем необходимость изменения) глобальных настроек оболочки.

Ваш ответ на вопрос