it-swarm.cn

如何遍历文件行?

说我有这个文件:

_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一次被分配整个文件。我应该改变什么?

63
Tobias Kienzler

for[〜#〜] ifs [〜#〜]

#!/bin/bash

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

但是请注意,它将跳过空行,因为newline是IFS空格字符,其序列计为1,而前导和尾随为忽略了。使用zshksh93(不是bash),则可以将其更改为IFS=$'\n\n'表示不对换行符进行特殊处理,但是请注意,所有尾随换行符(因此包括尾随的空行)将始终被命令删除代换。

带有read (不再有cat):

#!/bin/bash

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

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

76
wag

为了它的价值,我需要经常这样做,并且永远不记得使用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
1
Jonathan H