如何遍历文件行?


61

说我有这个文件:

hello
world
hello world

这个程序

#!/bin/bash

for i in $(cat $1); do
    echo "tester: $i"
done

输出

tester: hello
tester: world
tester: hello
tester: world

我想让for每行的迭代分别忽略空白,即最后两行应替换为

tester: hello world

使用引号会for i in "$(cat $1)";导致i一次分配整个文件。我应该改变什么?

Answers:


69

forIFS

#!/bin/bash

IFS=$'\n'       # make newlines the only separator
set -f          # disable globbing
for i in $(cat < "$1"); do
  echo "tester: $i"
done

但是请注意,由于换行符是IFS空格字符,它将跳过空行,其序列计数为1,并且忽略前导和尾随的字符。随着zshksh93(不bash),你可以将其更改IFS=$'\n\n'为新行不被特殊对待,但是请注意,所有尾随换行符(因此包括尾随的空行)总是会被命令替换被删除。

read(没有更多cat):

#!/bin/bash

while IFS= read -r line; do
  echo "tester: $line"
done < "$1"

此处保留了空行,但是请注意,如果未用换行符正确分隔,则会跳过最后一行。


5
谢谢,我不知道一个人可以<陷入一个完整的循环。尽管现在说得很对,我还是看到了
Tobias Kienzler 2011年

1
我看到IFS \ read -r line' in second example. Is really 需要IFS =`吗?恕我直言,足以说:while read -r line; do echo "tester: $line"; done < "$1"
Grzegorz Wierzowiecki 2012年

4
@GrzegorzWierzowiecki IFS=关闭对开头和结尾空格的剥离。见while IFS= read..,为什么IFS有没有影响?
Gilles 2014年

0

为了它的价值,我需要经常这样做,并且永远无法记住确切的使用方法while IFS= read...,因此我在bash配置文件中定义了以下函数:

# iterate the line of a file and call input function
iterlines() {
    (( $# < 2 )) && { echo "Usage: iterlines <File> <Callback>"; return; }
    local File=$1
    local Func=$2
    n=$(cat "$File" | wc -l)
    for (( i=1; i<=n; i++ )); do
        "$Func" "$(sed "${i}q;d" "$File")"
    done
}

此函数首先确定文件中的行数,然后用于sed提取一行一行,并将每一行作为单个字符串参数传递给任何给定函数。我想这对于大文件来说可能真的效率低下,但是到目前为止,这对我来说并不是一个问题(当然,有关如何改善这种欢迎的建议)。

IMO的用法很不错:

>> cat example.txt # note the use of spaces, whitespace, etc.
a/path

This is a sentence.
"wi\th quotes"
$End
>> iterlines example.txt echo # preserves quotes, $ and whitespace
a/path

This is a sentence.
"wi\th quotes"
$End
>> x() { echo "$#"; }; iterlines example.txt x # line always passed as single input string
1
1 
1
1
1
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.