我有一个名为error_log
的apache文件,我想使用sed
命令查看该文件的第一行和最后一行。您能帮我怎么做?
我知道如何使用head
和tail
命令来执行此操作,但是我很好奇在sed
命令中是否也可以。
我已经读过man sed
并在Google上搜索了很多,但不幸的是没有找到任何东西。
答案 0 :(得分:1)
第一行:
sed '2,$d' error_log
最后一行:
sed '$!d' error_log
答案 1 :(得分:1)
这将起作用:
sed -n '1p ; $p' error_log
1p
将打印第一行,$p
将打印最后一行。
作为建议,不但man sed
,而且要看info sed。您可以在第2.1段中找到有关您的问题的一些示例。
答案 2 :(得分:1)
这可能对您有用(GNU sed):
sed '1b;$b;d' file
所有sed命令都可以以地址或正则表达式为前缀。地址是行号或代表最后一行的$
。如果没有地址或正则表达式,则以下命令将应用于所有其他行。
正常sed周期在模式空间中显示每行输入(减去换行)。然后应用sed命令,循环的最后一步是重新附加换行符并打印结果。
b
命令控制命令流;如果它本身跳出了以下sed命令,就跳到循环的最后一个动作,即重新连接换行符并打印结果。
d
命令删除了模式空间,并且由于没有要打印的内容,因此不执行进一步的处理(包括重新附加换行符和打印结果)。
因此上述解决方案将打印第一行和最后一行,并删除其余行。
Sed具有一些命令行选项,其中之一是模式空间-n
的隐式打印结果。 p
命令显示模式空间的当前状态。因此,上述解决方案的对偶是:
sed -n '1p;$p' file
如果输入文件只有一行,则第一种解决方案将只打印一行,而第二种解决方案将同一行打印两次。同样,如果输入了多个文件,则除非使用-i
选项,否则两种解决方案都将打印第一个文件的第一行和最后一个文件的最后一行,在这种情况下,将修改每个文件。 -s
选项可在不修改每个文件的情况下复制此文件,但会将结果流式传输到stdout,就像每个文件都被单独处理一样。
答案 3 :(得分:1)
根据您的新要求,如果输入文件只有1行,则什么也不输出(请参见How to find only the first and last line of a file using sed):
awk 'NR==1{first=$0} {last=$0} END{if (NR>1) print first ORS last}'
原始答案:
从表面上看,这是您可以在sed中轻松完成的事情之一:
$ seq 3 7
3
4
5
6
7
$ seq 3 7 | sed -n '1p; $p'
3
7
,但是如何处理像输入的一行这样的边缘情况却不是很明显,例如这真的是正确的输出吗?
$ printf 'foo\n' | sed -n '1p; $p'
foo
foo
还是正确的输出:
foo
,如果是后者,如何调整sed命令以产生输出? @potong建议使用GNU sed命令:
$ printf 'foo\n' | sed '1b;$b;d'
foo
可以工作,但可能仅适用于GNU(idk),更重要的是,它看起来与我们开始使用的命令不太相似,因此对需求的最小更改意味着可以使用不同的构造完全重写。
现在,如果要增强它,例如仅在文件包含foo
的情况下才打印第一行和最后一行,该怎么办?我希望这将是sed的又一项挑战性练习,并且可能还涉及非便携式构造。
当您可以使用诸如awk之类的其他工具并以简单,一致,可移植的语法来完成您想做的事情时,学习如何使用sed进行操作就毫无意义了
$ seq 3 7 |
awk 'NR==1{first=$0} {last=$0} END{print first ORS last}'
3
7
$ printf 'foo\n' |
awk 'NR==1{first=$0} {last=$0} END{print first ORS last}'
foo
foo
$ printf 'foo\n' |
awk 'NR==1{first=$0} {last=$0} END{print first (NR>1 ? ORS last : "")}'
foo
$ printf '3\nfoo\n7\n' |
awk 'NR==1{first=$0} /foo/{f=1} {last=$0} END{if (f) print first (NR>1 ? ORS last : "")}'
3
7
$ printf '3\nbar\n7\n' |
awk 'NR==1{first=$0} /foo/{f=1} {last=$0} END{if (f) print first (NR>1 ? ORS last : "")}'
$
注意:
现在,如果要对多个文件(如以下命令创建的文件)执行该操作,怎么办?
$ seq 3 7 > file1
$ seq 12 25 > file2
使用awk,您只需将行存储在数组中即可在END中打印:
$ awk 'FNR==1{first[++cnt]=$0} {last[cnt]=$0}
END{for (i=1;i<=cnt;i++) print first[i] ORS last[i]}' file1 file2
3
7
12
25
或使用GNU awk,您可以从ENDFILE打印它们:
$ awk 'FNR==1{first=$0} {last=$0} ENDFILE{print first ORS last}' file1 file2
3
7
12
25
用sed吗?留给读者的练习。