使用Bash一次读取n行

Loo*_*ast 39 bash

我读了这个help read页面,但仍然没有意义.不知道使用哪个选项.

如何使用Bash一次读取N行?

Fms*_*rat 35

虽然所选答案有效,但实际上不需要单独的文件句柄.只需在原始句柄上使用read命令就可以正常运行.

这是两个例子,一个带字符串,一个带文件:

# Create a dummy file
echo -e "1\n2\n3\n4" > testfile.txt

# Loop through and read two lines at a time
while read -r ONE; do
    read -r TWO
    echo "ONE: $ONE TWO: $TWO"
done < testfile.txt

# Create a dummy variable
STR=$(echo -e "1\n2\n3\n4")

# Loop through and read two lines at a time
while read -r ONE; do
    read -r TWO
    echo "ONE: $ONE TWO: $TWO"
done <<< "$STR"
Run Code Online (Sandbox Code Playgroud)

将以上脚本作为脚本输出(两个循环的输出相同):

ONE: 1 TWO: 2
ONE: 3 TWO: 4
ONE: 1 TWO: 2
ONE: 3 TWO: 4
Run Code Online (Sandbox Code Playgroud)


gni*_*urf 29

Bash≥4你可以这样使用mapfile:

while mapfile -t -n 10 ary && ((${#ary[@]})); do
    printf '%s\n' "${ary[@]}"
    printf -- '--- SNIP ---\n'
done < file
Run Code Online (Sandbox Code Playgroud)

那是一次读10行.

  • 这似乎是最有效和最优雅的方法,因此应该是公认的答案.如果添加"&&(($ {#ary [@]}))`的解释,那就太棒了. (5认同)
  • @Oliver:感谢您的评论和反对票。不幸的是,编程并不简单。您链接的第一个答案很难扩展:如果您想一次阅读 120 行怎么办?如果您想一次读取 `N` 次(其中 `N` 是一个变量)怎么办?您链接的第二个答案已损坏,以防您的流/文件包含单引号。也许我的方法不是用户友好的,但至少它是正确的并且可以毫无问题地扩展。 (5认同)
  • @codeforester`&amp;&amp;((($ {#ary [@]])))`本质上意味着直到有几行要读取(数组中的元素数返回某值) (2认同)

Aar*_*lla 23

这比它看起来更难.问题是如何保持文件句柄.

解决方案是创建另一个新文件句柄,其工作方式与stdin(文件句柄0)相同,但是是独立的,然后根据需要从中读取.

#!/bin/bash

# Create dummy input
for i in $(seq 1 10) ; do echo $i >> input-file.txt ; done

# Create new file handle 5
exec 5< input-file.txt

# Now you can use "<&5" to read from this file
while read line1 <&5 ; do
        read line2 <&5
        read line3 <&5
        read line4 <&5

        echo "Four lines: $line1 $line2 $line3 $line4"
done

# Close file handle 5
exec 5<&-
Run Code Online (Sandbox Code Playgroud)

  • 再次阅读,我也不知道为什么我解释了如何创建一个新的文件句柄而不是使用stdio: - / (3认同)
  • 多亏了这一点,我用它作为我的解决方案的基础.这有效,但不需要额外的文件句柄.请参阅下面的相似解决方案,但不需要第二个句柄. (2认同)

Mik*_*der 17

最简单的方法 - 非常不言自明.它类似于@Fmstrat提供的方法,除了第二个read语句在之前do.

while read first_line; read second_line
do
    echo "$first_line" "$second_line"
done
Run Code Online (Sandbox Code Playgroud)

您可以通过管道多行输入来使用它:

seq 1 10 | while read first_line; read second_line 
do
    echo "$first_line" "$second_line"
done
Run Code Online (Sandbox Code Playgroud)

输出:

1 2
3 4
5 6
7 8
9 10
Run Code Online (Sandbox Code Playgroud)


nav*_*ram 14

那要简单得多!:)

cat input-file.txt | xargs -L 10 ./do_something.sh
Run Code Online (Sandbox Code Playgroud)

或者

cat input-file.txt | xargs -L 10 echo
Run Code Online (Sandbox Code Playgroud)

  • 如果输入行包含对 shell 有意义的字符,则此方法会出现问题。例如,带有单个撇号的文本将成为未终止的引号并停止处理。 (4认同)

alb*_*rji 6

我不认为有一种方法可以在bash中本地执行它,但是可以创建一个方便的功能:

#
# Reads N lines from input, keeping further lines in the input.
#
# Arguments:
#   $1: number N of lines to read.
#
# Return code:
#   0 if at least one line was read.
#   1 if input is empty.
#
function readlines () {
    local N="$1"
    local line
    local rc="1"

    # Read at most N lines
    for i in $(seq 1 $N)
    do
        # Try reading a single line
        read line
        if [ $? -eq 0 ]
        then
            # Output line
            echo $line
            rc="0"
        else
            break
        fi
    done

    # Return 1 if no lines where read
    return $rc
}
Run Code Online (Sandbox Code Playgroud)

通过这样做,可以轻松地在数据的N行块上循环

while chunk=$(readlines 10)
do
    echo "$chunk" | ... # Whatever processing
done
Run Code Online (Sandbox Code Playgroud)

在这个循环中,$ chunk在每次迭代时将包含10个输入行,除了最后一行,它将包含最后一行输入,可能小于10但总是大于0.