如何使用 Bash 遍历文件中的每一行?

问题描述 投票:0回答:10

给定一个包含多行的文本文件,我想遍历 Bash 脚本中的每一行。我曾尝试使用

cut
,但
cut
不接受
\n
(换行符)作为分隔符。

这是我正在使用的文件示例:

one
two 
three 
four

有谁知道我如何在 Bash 中遍历此文本文件的每一行?

bash loops iteration
10个回答
87
投票

我发现自己遇到了同样的问题,这对我有用:

cat file.cut | cut -d$'\n' -f1

或:

cut -d$'\n' -f1 file.cut

30
投票

使用

cat
连接或显示。这里不需要它。

file="/path/to/file"
while read line; do
  echo "${line}"
done < "${file}"

3
投票

只需使用:

echo -n `cut ...`

这抑制了 最后


2
投票
cat FILE|while read line; do # 'line' is the variable name
   echo "$line" # do something here
done

或(见评论):

while read line; do # 'line' is the variable name
   echo "$line" # do something here
done < FILE

2
投票

所以,已经提供了一些非常好的(可能更好)的答案。但是看看原始问题的措辞,想要使用 BASH for 循环,令我惊讶的是没有人提到更改字段分隔符 IFS 的解决方案。这是一个纯粹的 bash 解决方案,就像 accepted read line

old_IFS=$IFS
IFS='\n'
for field in $(<filename)
do your_thing;
done
IFS=$old_IFS

2
投票

如果您确定输出将始终以换行符分隔,请使用

head -n 1
代替
cut -f1
(请注意,您在脚本中提到了一个 for 循环,而您的问题最终与脚本无关)。

许多其他答案,包括已接受的答案,不必要地有多行。无需在多行上执行此操作或更改系统上的默认分隔符。

此外,Ivan 提供的带有

-d$'\n'
的解决方案在 Mac OSX 或 CentOS 7 上对我都不起作用。由于他的回答已有四年历史,因此我认为
$
字符的逻辑一定发生了一些变化情况。


2
投票

带有输入重定向和
read
命令的 While 循环。

您不应该使用

cut
对文件中的每一行执行顺序迭代,因为
cut
并非旨在执行此操作。

从每个文件中打印选定的部分行到标准输出。 —

man cut

TL;博士

您应该将 while 循环与

read -r
命令一起使用,并将标准输入重定向到函数范围内的文件,其中
IFS
设置为
\n
并在使用
-E
时使用
echo

processFile() {          # Function scope to prevent overwriting IFS globally
  file="$1"              # Any file that exists
  local IFS="\n"         # Allows spaces and tabs
  while read -r line; do # Read exits with 1 when done; -r allows \
    echo -E "$line"      # -E allows printing of \ instead of gibberish
  done < $file           # Input redirection allows us to read file from stdin
}
processFile /path/to/file

迭代

为了遍历文件的每一行,我们可以使用 while 循环。这将使我们可以根据需要进行多次迭代。

while <condition>; do
  <body>
done

让我们的文件准备好阅读

我们可以使用

read
命令将来自标准输入的单行存储在变量中。在我们可以使用它从我们的文件中读取一行之前,我们需要重定向标准输入以指向我们的文件。我们可以通过输入重定向来做到这一点。根据 bashman 页面,重定向的语法是
[fd]<file
其中
fd
默认为标准输入(也称为文件描述符
0
)。我们可以将它放在 while 循环之前或之后。

while <condition>; do
  <body>
done < /path/to/file

# or the non-traditional way
</path/to/file while <condition>; do
  <body>
done

读取文件并结束循环

现在我们的文件可以从标准输入读取,我们可以使用

read
。在我们的上下文中,
read
的语法是
read [-r] var...
,其中
-r
保留了
\
(反斜杠)字符,而不是将其用作转义序列字符,而
var
是存储变量的名称输入。您可以有多个变量来存储输入的片段,但我们只需要一个变量来读取整行。除此之外,要保留
echo
的任何输出中的任何反斜杠,您可能需要使用
-E
标志来禁用反斜杠转义的解释。如果您有任何缩进(空格或制表符),您需要暂时将
IFS
(输入字段分隔符)变量更改为仅
"\n"
;通常它被设置为
" \t\n"
.

main() {
  local IFS="\n"
  read -r line
  echo -E "$line"
}

main

我们如何使用
read
来结束我们的 while 循环?

据我所知,只有一种可靠的方法可以确定您何时使用

read
完成读取文件:检查
read
的退出值。如果
read
的退出值是
0
那么我们成功读取了一行,如果它是
1
或更高那么我们到达了 EOF(文件末尾)。考虑到这一点,我们可以在 while 循环的条件部分调用
read

processFile() {
  # Could be any file you want hardcoded or dynamic
  file="$1"

  local IFS="\n"
  while read -r line; do
    # Process line here
    echo -E "$line"
  done < $file
}

processFile /path/to/file1
processFile /path/to/file2

通过 Explain Shell 对上述代码的可视分解。


0
投票

如果我正在执行命令并想剪切输出但它有多行我发现这样做很有帮助

echo $([command]) | cut [....]

这将

[command]
的所有输出放在一行上,这样更容易处理。


0
投票

迭代文件中记录的最简单方法是通过

for
中的
bash
循环。

#!/bin/bash
echo 'Showing the records in the file';
for i in `cat myfile.txt`; do echo $i; done;  # this will show records line by line
echo 'End of the script';

-2
投票

我的意见是“cut”用' ' 作为其默认分隔符。 如果你想使用 cut,我有两种方法:

    cut -d^M -f1 file_cut

我通过在 Ctrl+V 后单击 Enter 来制作 ^M。另一种方式是

    cut -c 1- file_cut

有帮助吗?

© www.soinside.com 2019 - 2024. All rights reserved.