试图调试服务器的一个问题,我唯一的日志文件是一个20GB的日志文件(甚至没有时间戳!)为什么人们使用System.out.println()作为日志?在生产吗? !)

使用grep,我找到了我想要查看的文件区域,第347340107行。

除了做一些

head -<$LINENUM + 10> filename | tail -20 

... 这将需要头读取日志文件的前3.47亿行,是否有一个快速而简单的命令将行347340100 - 347340200(例如)转储到控制台?

我完全忘记了grep可以打印匹配前后的上下文…这很有效。谢谢!


你可以说GNU-grep

grep --context=10 ...

是什么:

tail -n +347340107 filename | head -n 100

我没有测试,但我认为这是可行的。


用sed -e '1,N d;M q'你将打印从N+1到M的行,这可能比grep -C更好一点,因为它不会尝试将行与模式匹配。


我发现了其他两个解决方案,如果你知道行号,但没有其他(没有grep可能):

假设你需要第20到40行,

sed -n '20,40p;41q' file_name

or

awk 'FNR>=20 && FNR<=40' file_name

When using sed it is more efficient to quit processing after having printed the last line than continue processing until the end of the file. This is especially important in the case of large files and printing lines at the beginning. In order to do so, the sed command above introduces the instruction 41q in order to stop processing after line 41 because in the example we are interested in lines 20-40 only. You will need to change the 41 to whatever the last line you are interested in is, plus one.


我首先将文件分成如下几个较小的文件

$ split --lines=50000 /path/to/large/file /path/to/output/file/prefix

然后对结果文件进行grep。


不,没有,文件不是行寻址的。

在文本文件中,没有固定时间的方法来找到第n行的开始。您必须流遍文件并计算换行符。

使用你拥有的最简单/最快的工具来完成这项工作。对我来说,使用head比使用grep更有意义,因为后者要复杂得多。我并不是说“grep很慢”,它确实不是,但是如果它比head更快,我会感到惊讶。那基本上就是脑袋里的虫子了。


# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3,  efficient on large files 

方法3对大文件有效

显示特定线条的最快方式


Sed还需要读取数据来计算行数。 唯一可能的快捷方式是文件中有上下文/顺序可以操作。例如,如果日志行前面有固定宽度的时间/日期等。 您可以使用look Unix实用程序在文件中查找特定的日期/时间


我更喜欢更少的

输入50%到文件的一半, 43210G转到43210行 :43210来做同样的事情

诸如此类。

更好的方法是:点击v以在该位置开始编辑(当然是在vim中!)现在,请注意vim具有相同的键绑定!


基于Sklivvz的回答,这里有一个可以放入.bash_aliases文件中的很好的函数。当从文件的前面打印东西时,它对巨大的文件是有效的。

function middle()
{
    startidx=$1
    len=$2
    endidx=$(($startidx+$len))
    filename=$3

    awk "FNR>=${startidx} && FNR<=${endidx} { print NR\" \"\$0 }; FNR>${endidx} { print \"END HERE\"; exit }" $filename
}

要通过<line#>显示<textfile>中的一行,只需这样做:

perl -wne 'print if $. == <line#>' <textfile>

如果你想用更强大的方法用正则表达式来显示一行范围——我不会说为什么grep是一个坏主意,这应该是相当明显的——这个简单的表达式将在一次传递中显示你的范围,这是你在处理~20GB文本文件时想要的:

perl -wne 'print if m/<regex1>/ .. m/<regex2>/' <filename>

(提示:如果你的regex中有/,使用类似m!<regex>!相反)

这将打印出<filename>,从匹配<regex1>的行开始,直到(并包括)匹配<regex2>的行。

不需要一个向导,就可以看到一些调整可以使它更加强大。

最后一点:perl,因为它是一种成熟的语言,有许多隐藏的增强来提高速度和性能。考虑到这一点,它成为这种操作的明显选择,因为它最初是为处理大型日志文件、文本、数据库等而开发的。


Use

x=`cat -n <file> | grep <match> | awk '{print $1}'`

在这里,您将获得发生匹配的行号。

现在可以使用下面的命令打印100行

awk -v var="$x" 'NR>=var && NR<=var+100{print}' <file>

或者你也可以使用“sed”

sed -n "${x},${x+100}p" <file>

你可以试试这个命令:

egrep -n "*" <filename> | egrep "<line number>"

简单的perl!如果你想从文件中获得第1、3和5行,输入/etc/passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

你可以使用ex命令,一个标准的Unix编辑器(现在是Vim的一部分),例如。

显示单行(例如第二行): Ex +2p -scq file.txt 对应的sed语法:sed -n '2p' file.txt 行范围(例如2-5行): Ex +2,5p -scq file.txt Sed语法:Sed -n '2,5p' file.txt 从给定的行到末尾(例如,第5行到文件末尾): Ex +5,p -scq file.txt Sed语法:Sed -n '2,$p' file.txt 多行范围(例如2-4行和6-8行): Ex +2,4p +6,8p -scq file.txt Sed语法:Sed -n '2,4p;6,8p' file.txt

以上命令可以用下面的测试文件进行测试:

seq 1 20 > file.txt

解释:

+或-c后跟命令-读取文件后执行(vi/vim)命令, -s -静默模式,也使用当前终端作为默认输出, Q后面加-c是退出编辑器的命令(add !强制退出,例如-scq!)。


我很惊讶,只有另一个答案(由Ramana Reddy)建议在输出中添加行号。下面搜索所需的行号并为输出上色。

file=FILE
lineno=LINENO
wb="107"; bf="30;1"; rb="101"; yb="103"
cat -n ${file} | { GREP_COLORS="se=${wb};${bf}:cx=${wb};${bf}:ms=${rb};${bf}:sl=${yb};${bf}" grep --color -C 10 "^[[:space:]]\\+${lineno}[[:space:]]"; }

得到证实

Ubuntu/Debian 安装:

$ sudo apt-get install ack-grep

然后运行:

$ ack --lines=$START-$END filename

例子:

$ ack --lines=10-20 filename

来自$ man ack:

--lines=NUM
    Only print line NUM of each file. Multiple lines can be given with multiple --lines options or as a comma separated list (--lines=3,5,7). --lines=4-7 also works. 
    The lines are always output in ascending order, no matter the order given on the command line.

如果你的行号是100来读取

head -100 filename | tail -1

打印行5

sed -n '5p' file.txt
sed '5q' file.txt

打印第5行以外的所有内容

`sed '5d' file.txt

我用谷歌创建的

#!/bin/bash
#removeline.sh
#remove deleting it comes move line xD

usage() {                                 # Function: Print a help message.
  echo "Usage: $0 -l LINENUMBER -i INPUTFILE [ -o OUTPUTFILE ]"
  echo "line is removed from INPUTFILE"
  echo "line is appended to OUTPUTFILE"
}
exit_abnormal() {                         # Function: Exit with error.
  usage
  exit 1
}

while getopts l:i:o:b flag
do
    case "${flag}" in
        l) line=${OPTARG};;
        i) input=${OPTARG};;
        o) output=${OPTARG};;
    esac
done

if [ -f tmp ]; then
echo "Temp file:tmp exist. delete it yourself :)"
exit
fi

if [ -f "$input" ]; then
   re_isanum='^[0-9]+$'
   if ! [[ $line =~ $re_isanum ]] ; then
      echo "Error: LINENUMBER must be a positive, whole number."
      exit 1
   elif [ $line -eq "0" ]; then
      echo "Error: LINENUMBER must be greater than zero."
      exit_abnormal
   fi
   if [ ! -z $output ]; then
      sed -n "${line}p" $input >> $output
   fi
   if [ ! -z $input ]; then
      # remove this sed command and this comes move line to other file
      sed "${line}d" $input > tmp && cp tmp $input
   fi
fi

if [ -f tmp ]; then
rm tmp
fi