868

我有以下 .txt 文件:

Marco
Paolo
Antonio

我想逐行阅读它,并且对于每一行我想将一个 .txt 行值分配给一个变量。假设我的变量是$name,流程是:

  • 从文件中读取第一行
  • 分配$name=“马可”
  • 做一些任务$name
  • 从文件中读取第二行
  • 分配$name=“保罗”
4

10 回答 10

1557

下面逐行读取作为参数传递的文件:

while IFS= read -r line; do
    echo "Text read from file: $line"
done < my_filename.txt

这是在循环中从文件中读取行的标准形式。解释:

  • IFS=(或IFS='')防止前导/尾随空格被修剪。
  • -r防止反斜杠转义被解释。

或者你可以把它放在一个 bash 文件帮助脚本中,示例内容:

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

如果将以上内容保存到具有 filename 的脚本中readfile,则可以按如下方式运行:

chmod +x readfile
./readfile filename.txt

如果文件不是标准的 POSIX 文本文件(= 不是由换行符终止),则可以修改循环以处理尾随部分行:

while IFS= read -r line || [[ -n "$line" ]]; do
    echo "Text read from file: $line"
done < "$1"

在这里,|| [[ -n $line ]]如果最后一行不以 a 结尾,则防止它被忽略\n(因为read在遇到 EOF 时返回非零退出代码)。

如果循环内的命令也从标准输入读取,则使用的文件描述符read可能会变成其他东西(避免使用标准文件描述符),例如:

while IFS= read -r -u3 line; do
    echo "Text read from file: $line"
done 3< "$1"

(非 Bash shell 可能不知道read -u3;请read <&3改用。)

于 2012-06-07T09:53:38.333 回答
334

我鼓励您使用以下-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"
于 2012-06-07T10:24:31.930 回答
145

使用以下 Bash 模板应该允许您一次从文件中读取一个值并对其进行处理。

while read name; do
    # Do what you want to $name
done < filename
于 2012-06-07T09:55:10.487 回答
89
#! /bin/bash
cat filename | while read LINE; do
    echo $LINE
done
于 2016-01-12T11:25:30.863 回答
25

采用:

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

如果你有IFS不同的设置,你会得到奇怪的结果。

于 2014-04-17T20:40:27.633 回答
21

许多人发布了一个过度优化的解决方案。我不认为这是不正确的,但我谦虚地认为,一个不太优化的解决方案将是可取的,让每个人都可以轻松地理解它是如何工作的。这是我的建议:

#!/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"
于 2016-10-16T10:30:40.243 回答
11

如果您需要同时处理输入文件和用户输入(或来自标准输入的任何其他内容),请使用以下解决方案:

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

基于接受的答案bash-hackers 重定向教程

在这里,我们打开作为脚本参数传递的文件的文件描述符 3,并告诉read使用这个描述符作为输入 ( -u 3)。因此,我们将默认输入描述符 (0) 附加到终端或另一个输入源,以便能够读取用户输入。

于 2016-02-01T12:58:05.137 回答
7

对于正确的错误处理:

#!/bin/bash

set -Ee    
trap "echo error" EXIT    
test -e ${FILENAME} || exit
while read -r line
do
    echo ${line}
done < ${FILENAME}
于 2017-12-21T19:49:52.753 回答
1

使用 bash 中的 IFS(内部字段分隔符)工具,定义用于将行分隔为标记的字符,默认包括 < tab > /< space > /< newLine >

第 1 步:加载文件数据并插入列表:

# declaring array list and index iterator
declare -a array=()
i=0

# reading file in row mode, insert each line into array
while IFS= read -r line; do
    array[i]=$line
    let "i++"
    # reading from file path
done < "<yourFullFilePath>"

第 2 步:现在迭代并打印输出:

for line in "${array[@]}"
  do
    echo "$line"
  done

回显数组中的特定索引:访问数组中的变量:

echo "${array[0]}"
于 2019-07-23T19:50:11.723 回答
-7

以下将仅打印出文件的内容:

cat $Path/FileName.txt

while read line;
do
echo $line     
done
于 2019-01-09T17:16:40.960 回答