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

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


当前回答

我将上面的一些答案放入了一个简短的bash脚本中,您可以将其放入名为get.sh的文件中,并链接到/usr/local/bin/get(或您喜欢的任何其他名称)。

#!/bin/bash
if [ "${1}" == "" ]; then
    echo "error: blank line number";
    exit 1
fi
re='^[0-9]+$'
if ! [[ $1 =~ $re ]] ; then
    echo "error: line number arg not a number";
    exit 1
fi
if [ "${2}" == "" ]; then
    echo "error: blank file name";
    exit 1
fi
sed "${1}q;d" $2;
exit 0

确保它可通过

$ chmod +x get

将其链接以使其在PATH上可用

$ ln -s get.sh /usr/local/bin/get

其他回答

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

创建文件:~/.functions

添加内容:

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

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

source~/.函数

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

获取行441 myfile.txt

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:在某个位置插入一行

以上所有答案都直接回答了这个问题。但这是一个不那么直接的解决方案,但可能是一个更重要的想法,可以引起人们的思考。

由于行长度是任意的,因此需要读取文件第n行之前的所有字节。如果您有一个巨大的文件或需要多次重复此任务,并且此过程非常耗时,那么您应该认真考虑是否应该首先以不同的方式存储数据。

真正的解决方案是有一个索引,例如在文件的开头,指示行开始的位置。您可以使用数据库格式,或者在文件开头添加一个表。或者,创建一个单独的索引文件,与大型文本文件一起使用。

例如,您可以为换行符创建一个字符位置列表:

awk 'BEGIN{c=0;print(c)}{c+=length()+1;print(c+1)}' file.txt > file.idx

然后用tail读取,它实际上直接查找文件中的适当点!

例如获得线1000:

tail -c +$(awk 'NR=1000' file.idx) file.txt | head -1

这可能不适用于2字节/多字节字符,因为awk是“字符识别”的,但tail不是。我还没有对一个大文件进行测试。另请参阅此答案。或者,将文件拆分为更小的文件!

这不是一个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;
}

在查看了顶部答案和基准之后,我实现了一个小助手函数:

function nth {
    if (( ${#} < 1 || ${#} > 2 )); then
        echo -e "usage: $0 \e[4mline\e[0m [\e[4mfile\e[0m]"
        return 1
    fi
    if (( ${#} > 1 )); then
        sed "$1q;d" $2
    else
        sed "$1q;d"
    fi
}

基本上,您可以以两种方式使用它:

nth 42 myfile.txt
do_stuff | nth 42