有没有一种“规范”的方法?我一直在使用head-n|tail-1来完成这个任务,但我一直在想是否有一个Bash工具专门从文件中提取一行(或一系列行)。
我所说的“规范”是指一个主要功能就是这样做的程序。
有没有一种“规范”的方法?我一直在使用head-n|tail-1来完成这个任务,但我一直在想是否有一个Bash工具专门从文件中提取一行(或一系列行)。
我所说的“规范”是指一个主要功能就是这样做的程序。
当前回答
以上所有答案都直接回答了这个问题。但这是一个不那么直接的解决方案,但可能是一个更重要的想法,可以引起人们的思考。
由于行长度是任意的,因此需要读取文件第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,下面是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行,请执行以下操作:
a=4
sed -e $a'q:d' file
这里的“-e”标志用于将脚本添加到要执行的命令中。
我将上面的一些答案放入了一个简短的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
以上所有答案都直接回答了这个问题。但这是一个不那么直接的解决方案,但可能是一个更重要的想法,可以引起人们的思考。
由于行长度是任意的,因此需要读取文件第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不是。我还没有对一个大文件进行测试。另请参阅此答案。或者,将文件拆分为更小的文件!
您也可以使用sed打印并退出:
sed -n '10{p;q;}' file # print line 10