在编写 Bash 脚本时,有时您会发现自己需要逐行读取文件。例如,您可能有一个文本文件,其中包含应由脚本处理的数据。
在本教程中,我们将讨论如何在 Bash 中逐行读取文件。
逐行读取文件语法#
逐行读取文件的最通用语法如下:
while IFS= read -r line; do
printf '%s\n' "$line"
done < input_file
或等效的单行版本:
while IFS= read -r line; do printf '%s\n' "$line"; done < input_file
它是如何工作的?
输入文件(input_file
) 是重定向到 while 循环的文件的名称。这read命令逐行处理文件,将每一行分配给line
多变的。处理完所有行后,while 循环终止。
默认情况下,read
命令将反斜杠解释为转义字符并删除所有前导和尾随空格,这有时可能会导致意外行为。要禁用反斜杠转义,我们使用以下命令调用命令-r
选项,并禁用修剪,内部字段分隔符(IFS
)被清除。
我们正在使用[printf
] 代替echo使代码更具可移植性并避免不必要的行为。例如,如果该行包含诸如“-e”之类的值,它将被视为回显选项。
逐行读取文件示例#
让我们看一下下面的例子。假设我们有一个名为distros.txt
包含一些最流行的 Linux 发行版的列表,及其以逗号分隔的包管理器 (,
):
发行版.txt
Ubuntu,apt
Debian,apt
CentOS,yum
Arch Linux,pacman
Fedora,dnf
要逐行读取文件,您可以在终端中运行以下代码:
while IFS= read -r line; do
printf '%s\n' "$line"
done < distros.txt
该代码按行读取文件,将每一行分配给一个变量,然后打印它。基本上,您会看到与使用显示文件内容相同的输出cat命令。
如果您只想打印使用 apt 的发行版怎么办?一种方法是使用if 语句并检查该行是否包含 apt子串
:
while IFS= read -r line; do
if [[ "$line" == *"apt"* ]]; then
printf '%s\n' "$line"
fi
done < distros.txt
Ubuntu,apt
Debian,apt
逐行读取文件时,还可以将多个变量传递给read
命令,该命令将根据以下内容将行拆分为字段IFS
。第一个字段分配给第一个变量,第二个字段分配给第二个变量,依此类推。如果字段多于变量,则剩余字段将分配给最后一个变量。
在下面的例子中,我们设置IFS
到一个逗号(,
)并传递两个变量distro
and pm
to the read
命令。从行首到第一个逗号的所有内容都将分配给第一个变量 (distro
),该行的其余部分将被分配给第二个变量(pm
):
while IFS=, read -r distro pm; do
printf '%s is the package manager for %s\n' "$pm" "$distro"
done < distros.txt
apt is the package manager for Ubuntu
apt is the package manager for Debian
yum is the package manager for CentOS
pacman is the package manager for Arch Linux
dnf is the package manager for Fedora
替代文件读取方法#
使用流程替代#
进程替换是一项功能,允许您将命令的输出用作文件:
while IFS= read -r line; do
printf '%s\n' "$line"
done < <(cat input_file )
使用此处的字符串#
这里 String 是一个变体这里的文档。字符串(cat input_file )
保留换行符:
while IFS= read -r line; do
printf '%s\n' "$line"
done <<< $(cat input_file )
使用文件描述符#
您还可以使用文件描述符向循环提供输入:
while IFS= read -r -u9 line; do
printf '%s\n' "$line"
done 9< input_file
当与文件描述符,使用 4 到 9 之间的数字以避免与 shell 内部文件描述符冲突。
结论#
在 Bash 中,我们可以使用 while 循环逐行读取文件read
命令。
如果您有任何问题或反馈,请随时发表评论。