我阅读了help read
页面,但仍然没有意义。不知道使用哪个选项。
如何使用Bash一次读取N行?
答案 0 :(得分:30)
虽然所选答案有效,但实际上不需要单独的文件句柄。只需在原始句柄上使用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"
运行上面的脚本将输出(两个循环的输出相同):
ONE: 1 TWO: 2
ONE: 3 TWO: 4
ONE: 1 TWO: 2
ONE: 3 TWO: 4
答案 1 :(得分:23)
如果Bash≥4,您可以使用commentEvent(event)
,如下所示:
mapfile
一次只读10行。
答案 2 :(得分:20)
这比它看起来更难。问题是如何保持文件句柄。
解决方案是创建另一个新文件句柄,其工作方式类似于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<&-
答案 3 :(得分:16)
最简单的方法 - 非常不言自明。它类似于@Fmstrat提供的方法,除了第二个read
语句在do
之前。
while read first_line; read second_line
do
echo "$first_line" "$second_line"
done
您可以通过管道多行输入来使用它:
seq 1 10 | while read first_line; read second_line
do
echo "$first_line" "$second_line"
done
输出:
1 2
3 4
5 6
7 8
9 10
答案 4 :(得分: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
}
通过这样做,可以通过执行类似
的操作轻松地遍历数据的N行块while chunk=$(readlines 10)
do
echo "$chunk" | ... # Whatever processing
done
在这个循环中,$ chunk在每次迭代时将包含10个输入行,除了最后一行,它将包含最后一行输入,可能小于10但总是大于0。
答案 5 :(得分:3)
那要简单得多! :)
cat input-file.txt | xargs -L 10 ./do_something.sh
或
cat input-file.txt | xargs -L 10 echo
答案 6 :(得分:2)
我提出了与@ albarji的答案非常相似的内容,但更简洁。
read_n() { for i in $(seq $1); do read || return; echo $REPLY; done; }
while lines="$(read_n 5)"; do
echo "========= 5 lines below ============"
echo "$lines"
done < input-file.txt
read_n
函数将从$1
读取stdin
行(使用重定向使其从文件中读取,就像内置的read
命令一样)。由于保留了read
的退出代码,因此您可以在循环中使用read_n
,如上例所示。
答案 7 :(得分:1)
根据您要执行的操作,您只需存储前一行。
LINE_COUNT=0
PREVLINE1=""
PREVLINE2=""
while read LINE
do LINE_COUNT=$(($LINE_COUNT+1));
if [[ $LINE_COUNT == 3 ]]; then
LINE_COUNT=0
# do whatever you want to do with the 3 lines
done
PREVLINE2="$PREVLINE1"
PREVLINE1="$LINE"
done
done < $FILE_IN
答案 8 :(得分:1)
我知道你问过bash,但我很惊讶这适用于zsh
#!/usr/bin/env zsh
cat 3-lines.txt | read -d\4 my_var my_other_var my_third_var
不幸的是,这不适用于bash
,至少是我尝试过的版本。
这里的“魔法”是-d\4
(这在bash中不起作用),它将行分隔符设置为EOT
字符,可以在cat
结尾处找到{1}}。或任何产生输出的命令。
如果您想阅读一系列N
项,bash有readarray
和mapfile
,可以读取N
行的文件,并将每行保存在一个位置数组。
修改强>
经过一些尝试,我发现这适用于bash:
$ read -d# a b
Hello
World
#
$ echo $a $b
Hello World
$
但是,我无法让{ cat /tmp/file ; echo '#'; } | read -d# a b
工作:(
答案 9 :(得分:1)
只需使用for
循环:
for i in $(seq 1 $N) ; do read line ; lines+=$line$'\n' ; done
在bash版本4中,您还可以使用mapfile
命令。
答案 10 :(得分:1)
echo
模拟包含两行输入的文件,如果需要,请在head -2
之前使用paste
:
IFS=\; read A B < <(echo -en "X1 X2\nY1 Y2\n" | paste -s -d\;)
如果你想在循环中读取行并创建对,并且行中只有单个单词,请使用:
while read NAME VALUE; do
echo "$NAME=$VALUE";
done < <(echo -en "M\n1\nN\n2\nO\n3\n" | xargs -L2 echo)
答案 11 :(得分:0)
以下是另一种方法:
//This will open the file and users can start adding variables.
cat > file
//After finished ctrl + D will close it
cat file|while read line;
do
//do some stuff here
done
答案 12 :(得分:0)
在这种情况下,awk是一种有趣的方式:
~$ cat test.txt
tom
tom@gmail.com
jack
jack@gmail.com
marry
marry@gmail.com
gogo
gogo@gmail.com
~$ cat test.txt | awk 'BEGIN{c=1}{a=c;if(a==2){print b" "$0;c=1} if(a==1){b=$0;c=2}}'
tom tom@gmail.com
jack jack@gmail.com
marry marry@gmail.com
gogo gogo@gmail.com
答案 13 :(得分:0)
从文件中读取n + 2行:-
2
4
6
8
。
。
等等
您可以尝试这种方式:-
cat fileName | awk '!((NR - 0) % 2)'
答案 14 :(得分:0)
您也可以使用 awk
对行进行分组:
$ seq -s ' ' 23 > file
$ cat file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
$ awk '(NR % 6 == 1) {print; for(i=1; i<6 && getline ; i++) { print }; printf "\n"}' RS=' ' ORS=' ' file
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23
答案 15 :(得分:-1)
mapfile -n通过Bash读取超出分配给数组的最后一行的额外行。已在4.2.35中修复
答案 16 :(得分:-1)
看完所有答案后,我认为以下是最简单的,即,更多的脚本编写者比任何其他解决方案都更了解它,但仅适用于少数项目:
while read -r var1 && read -r var2; do
echo "$var1" "$var2"
done < yourfile.txt
multi-command approach也很出色,但是虽然语法很直观,但鲜为人知:
while read -r var1; read -r var2; do
echo "$var1" "$var2"
done < yourfile.txt
它的优点是,对于大量项目,不需要连续行:
while
read -r var1
read -r var2
...
read -r varN
do
echo "$var1" "$var2"
done < yourfile.txt
xargs answer posted在理论上也不错,但是在实践中处理合并行并不是很明显。例如,我使用此技术想到的一种解决方案是:
while read -r var1 var2; do
echo "$var1" "$var2"
done <<< $(cat yourfile.txt | xargs -L 2 )
,但是它再次使用鲜为人知的<<<
运算符。但是,这种方法的优势在于,如果您的脚本最初是
while read -r var1; do
echo "$var1"
done <<< yourfile.txt
然后将其扩展为多行是很自然的:
while read -r var1 var2; do
echo "$var1" "$var2"
done <<< $(cat endpoints.txt | xargs -L 2 )
while read -r var1; do
read -r var2
echo "$var1" "$var2"
done < yourfile.txt
为了简单起见,是我要考虑的唯一的另一个,但从语法上讲,它不那么具有表现力。与&&
版本或多命令版本相比,它感觉不正确。