从标准输入中逐行读取 Bash
Read line by line from standard input Bash
我正在学习 bash 语言,考试轨道是这样说的:
It should read one input (from standard input) at a time (each entry
is a string and then ends with a newline).
我的问题有两个:
如何从 Bash 中的标准输入逐行读取?直到现在我使用 "read string"
但我不认为它一次读取一行。
我不知道这是否是一个愚蠢的问题,但是一旦创建了脚本,我如何才能将更多行作为输入提供给脚本(当然是从标准输入读取)。例如,我从 stdin 插入两行(hello
和 world
)。我如何给 bash 脚本这两行?
你可以这样做:
# array to hold all lines read
lines=()
# read all lines in lines array
while IFS= read -r line; do
lines+=( "$line" )
done < file
# read 3 more lines from stdin
for ((i=0; i<3; i++)); do
read -rp "Enter a line: " line
lines+=( "$line" )
done
- How do I read line by line from standard input in Bash? Until now I
used "read string" but I do not think that it reads a line at a time.
read
的原型是:
read [options] name[s ...]
read
会将 line
的输入读入 name name1 name2 ...
,根据 内部字段分隔符 的内容拆分行(IFS
). IFS
的默认值为 ' \t\n'
(即 space
tab
newline
)。如果您只向 read
提供一个变量,您会将整行读入该变量(除非您使用 -d
选项为 read
设置了新的分隔符)。如果您提供多个变量(例如 read -r name name1
),将根据 IFS
的当前值进行分词。这意味着如果您将字符串 hello world
提供给:
read -r name
name="hello world"
。另一方面,如果您将相同的字符串提供给:
read -r name name1
name="hello"
、name1="world"
。如果行中有多余的单词但只有 2 个变量怎么办?假设你的字符串现在是 "hello big wide world"
,会发生什么:
read -r name name1
name="hello"
、name1="big wide world"
。 string
中的单词按顺序分配给您的变量,如果没有足够的变量来保存字符串中的每个单词,最后一个变量将包含字符串中之前未分配的所有剩余单词。
您可以通过更改 IFS
来更改单词拆分的方式。仔细查看 anubhava 提供的答案作为示例。您可以自由指定您希望拆分单词的任何字符。 (有助于说解析 csv
文件以设置 IFS=$',\n'
并将单词拆分为 ','
而不是 space)
为确保将整行读入变量,您可以仅向 read
提供一个变量并设置 IFS='$\n'
以确保仅在 newline
上进行分词。 (注意: 将更改作为 while
循环的一部分提供,将 IFS
更改限制在该循环的范围内。例如:
while IFS='$\n' read -r line; do
# do whatever with line
done
将确保 stdin
上的每一行都将被读入 line
,同时在循环外保留正常的分词。在循环中,您可以将每一行添加到数组中,如 anubhava 在他的回答中所示。 (为了保留所有白色space IFS=
被使用)
我正在学习 bash 语言,考试轨道是这样说的:
It should read one input (from standard input) at a time (each entry is a string and then ends with a newline).
我的问题有两个:
如何从 Bash 中的标准输入逐行读取?直到现在我使用
"read string"
但我不认为它一次读取一行。我不知道这是否是一个愚蠢的问题,但是一旦创建了脚本,我如何才能将更多行作为输入提供给脚本(当然是从标准输入读取)。例如,我从 stdin 插入两行(
hello
和world
)。我如何给 bash 脚本这两行?
你可以这样做:
# array to hold all lines read
lines=()
# read all lines in lines array
while IFS= read -r line; do
lines+=( "$line" )
done < file
# read 3 more lines from stdin
for ((i=0; i<3; i++)); do
read -rp "Enter a line: " line
lines+=( "$line" )
done
- How do I read line by line from standard input in Bash? Until now I used "read string" but I do not think that it reads a line at a time.
read
的原型是:
read [options] name[s ...]
read
会将 line
的输入读入 name name1 name2 ...
,根据 内部字段分隔符 的内容拆分行(IFS
). IFS
的默认值为 ' \t\n'
(即 space
tab
newline
)。如果您只向 read
提供一个变量,您会将整行读入该变量(除非您使用 -d
选项为 read
设置了新的分隔符)。如果您提供多个变量(例如 read -r name name1
),将根据 IFS
的当前值进行分词。这意味着如果您将字符串 hello world
提供给:
read -r name
name="hello world"
。另一方面,如果您将相同的字符串提供给:
read -r name name1
name="hello"
、name1="world"
。如果行中有多余的单词但只有 2 个变量怎么办?假设你的字符串现在是 "hello big wide world"
,会发生什么:
read -r name name1
name="hello"
、name1="big wide world"
。 string
中的单词按顺序分配给您的变量,如果没有足够的变量来保存字符串中的每个单词,最后一个变量将包含字符串中之前未分配的所有剩余单词。
您可以通过更改 IFS
来更改单词拆分的方式。仔细查看 anubhava 提供的答案作为示例。您可以自由指定您希望拆分单词的任何字符。 (有助于说解析 csv
文件以设置 IFS=$',\n'
并将单词拆分为 ','
而不是 space)
为确保将整行读入变量,您可以仅向 read
提供一个变量并设置 IFS='$\n'
以确保仅在 newline
上进行分词。 (注意: 将更改作为 while
循环的一部分提供,将 IFS
更改限制在该循环的范围内。例如:
while IFS='$\n' read -r line; do
# do whatever with line
done
将确保 stdin
上的每一行都将被读入 line
,同时在循环外保留正常的分词。在循环中,您可以将每一行添加到数组中,如 anubhava 在他的回答中所示。 (为了保留所有白色space IFS=
被使用)