有没有一种“规范”的方法?我一直在使用head-n|tail-1来完成这个任务,但我一直在想是否有一个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可能是最接近和最简单的用法。

其他回答

已经有很多好答案了。我个人喜欢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

对于一个巨大的文件来说,头部和尾部的管道会很慢。我建议您这样做:

sed 'NUMq;d' file

其中NUM是要打印的行数;例如,sed’10q;d'文件以打印文件的第10行。

说明:

当行号为NUM时,NUMq将立即退出。

d将删除该行而不是打印该行;这在最后一行被禁止,因为q会导致退出时跳过脚本的其余部分。

如果变量中有NUM,则需要使用双引号而不是单引号:

sed "${NUM}q;d" file

这不是一个bash解决方案,但我发现顶级选择不能满足我的需求,例如,

sed 'NUMq;d' file

速度足够快,但挂了几个小时,没有告诉任何进展。我建议编译这个cpp程序并使用它来查找所需的行。您可以使用g++main.cpp编译它,其中main.cpp是包含以下内容的文件。我得到了一个,并执行了它/a.输出

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main() {
    string filename;
    cout << "Enter filename ";
    cin >> filename;

    int needed_row_number;
    cout << "Enter row number ";
    cin >> needed_row_number;

    int progress_line_count;
    cout << "Enter at which every number of rows to monitor progress ";
    cin >> progress_line_count;

    char ch;
    int row_counter = 1;
    fstream fin(filename, fstream::in);
    while (fin >> noskipws >> ch) {
        int ch_int = (int) ch;
        if (row_counter == needed_row_number) {
            cout << ch;
        }
        if (ch_int == 10) {
            if (row_counter == needed_row_number) {
                return 0;
            }
            row_counter++;
            if (row_counter % progress_line_count == 0) {
                cout << "Progress: line " << row_counter << endl;
            }
        }

    }
    return 0;
}

有了awk,速度相当快:

awk 'NR == num_line' file

如果为true,则执行awk的默认行为:{print$0}。


替代版本

如果您的文件恰好很大,最好在读取所需的行后退出。这样可以节省CPU时间请参见答案末尾的时间比较。

awk 'NR == num_line {print; exit}' file

如果要从bash变量中给出行号,可以使用:

awk 'NR == n' n=$num file
awk -v n=$num 'NR == n' file   # equivalent

查看使用exit节省了多少时间,特别是如果该行恰好位于文件的第一部分:

# Let's create a 10M lines file
for ((i=0; i<100000; i++)); do echo "bla bla"; done > 100Klines
for ((i=0; i<100; i++)); do cat 100Klines; done > 10Mlines

$ time awk 'NR == 1234567 {print}' 10Mlines
bla bla

real    0m1.303s
user    0m1.246s
sys 0m0.042s
$ time awk 'NR == 1234567 {print; exit}' 10Mlines
bla bla

real    0m0.198s
user    0m0.178s
sys 0m0.013s

因此,两者的差异是0.198秒对1.303秒,大约快了6倍。

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

创建文件:~/.functions

添加内容:

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

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

source~/.函数

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

获取行441 myfile.txt