有没有一种“规范”的方法?我一直在使用head-n|tail-1来完成这个任务,但我一直在想是否有一个Bash工具专门从文件中提取一行(或一系列行)。

我所说的“规范”是指一个主要功能就是这样做的程序。


当前回答

sed -n '2p' < file.txt

将打印第二行

sed -n '2011p' < file.txt

2011线

sed -n '10,33p' < file.txt

第10行到第33行

sed -n '1p;3p' < file.txt

第1和第3行

等等

对于使用sed添加行,您可以选中此项:

sed:在某个位置插入一行

其他回答

使用其他人提到的内容,我希望这是我的bash shell中一个快速而出色的函数。

创建文件:~/.functions

添加内容:

getline(){行=$1sed$line'q;2美元}

然后将其添加到~/.bash_profile中:

source~/.函数

现在,当您打开一个新的bash窗口时,您可以这样调用函数:

获取行441 myfile.txt

已经有很多好答案了。我个人喜欢awk。为了方便起见,如果您使用bash,只需将以下内容添加到~/.bash_profile中即可。下次登录时(或者如果您在本次更新后获取.bash_profile的源代码),您将有一个新的漂亮的“第n”函数可用于管道传输文件。

执行此命令或将其放入~/.bash_profile(如果使用bash)并重新打开bash(或执行源~/.bach_profile)

# print just the nth piped in line
nth () { awk -vlnum=${1} 'NR==lnum {print; exit}'; } 

然后,要使用它,只需通过管道。例如:

$ yes line | cat -n | nth 5
     5  line

作为CaffeineConnisseur非常有用的基准测试答案的后续。。。我很好奇“mapfile”方法与其他方法相比的速度有多快(因为没有测试),所以我自己尝试了一个快速而肮脏的速度比较,因为我手边有bash 4。在我做这项测试时,我在顶部答案的一条评论中提到了“tail|head”方法(而不是head|tail),因为人们都在称赞它。我没有使用的测试文件的大小;我能在短时间内找到的最好的文件是一个14M的谱系文件(用空格分隔的长行,略低于12000行)。

短版本:mapfile看起来比cut方法快,但比其他任何方法都慢,所以我称它为无用的。tail|head,OTOH,看起来可能是最快的,尽管与sed相比,这种大小的文件差异并不大。

$ time head -11000 [filename] | tail -1
[output redacted]

real    0m0.117s

$ time cut -f11000 -d$'\n' [filename]
[output redacted]

real    0m1.081s

$ time awk 'NR == 11000 {print; exit}' [filename]
[output redacted]

real    0m0.058s

$ time perl -wnl -e '$.== 11000 && print && exit;' [filename]
[output redacted]

real    0m0.085s

$ time sed "11000q;d" [filename]
[output redacted]

real    0m0.031s

$ time (mapfile -s 11000 -n 1 ary < [filename]; echo ${ary[0]})
[output redacted]

real    0m0.309s

$ time tail -n+11000 [filename] | head -n1
[output redacted]

real    0m0.028s

希望这有帮助!

这个问题被标记为Bash,下面是Bash(≥4)的方法:使用带有-s(跳过)和-n(计数)选项的mapfile。

如果需要获取文件文件的第42行:

mapfile -s 41 -n 1 ary < file

此时,您将得到一个数组ary,其中的字段包含文件行(包括尾部换行符),我们跳过了前41行(-s 41),并在读取一行(-n 1)后停止。这真的是第42行。要打印出来:

printf '%s' "${ary[0]}"

如果您需要一系列行,请说出范围42–666(含),并说您不想自己计算,然后将它们打印在标准输出上:

mapfile -s $((42-1)) -n $((666-42+1)) ary < file
printf '%s' "${ary[@]}"

如果您也需要处理这些行,那么存储尾随换行符并不太方便。在这种情况下,使用-t选项(trim):

mapfile -t -s $((42-1)) -n $((666-42+1)) ary < file
# do stuff
printf '%s\n' "${ary[@]}"

你可以让一个函数为你做这件事:

print_file_range() {
    # $1-$2 is the range of file $3 to be printed to stdout
    local ary
    mapfile -s $(($1-1)) -n $(($2-$1+1)) ary < "$3"
    printf '%s' "${ary[@]}"
}

没有外部命令,只有Bash内置命令!

哇,所有的可能性!

试试看:

sed -n "${lineNum}p" $file

或者根据您的Awk版本选择其中之一:

awk  -vlineNum=$lineNum 'NR == lineNum {print $0}' $file
awk -v lineNum=4 '{if (NR == lineNum) {print $0}}' $file
awk '{if (NR == lineNum) {print $0}}' lineNum=$lineNum $file

(您可能需要尝试nawk或gawk命令)。

是否有一种工具只打印特定的行?不是标准工具之一。然而,sed可能是最接近和最简单的用法。