假设您有一个 txt 文件,同时查看文件的前10行和后10行的命令是什么?
也就是说,如果文件长达200行,那么一次查看1-10行和190-200行。
首先是 file.ext 的10行,然后是最后的10行:
cat file.ext | head -10 && cat file.ext | tail -10
文件的最后10行,然后是前10行:
cat file.ext | tail -10 && cat file.ext | head -10
然后,你也可以将输出通过管道输送到其他地方:
(cat file.ext | head -10 && cat file.ext | tail -10 ) | your_program
head -10 file.txt; tail -10 file.txt
除此之外,您还需要编写自己的程序/脚本。
ed就是 standard text editor
ed
standard text editor
$ echo -e '1+10,$-10d\n%p' | ed -s file.txt
你可以把他们锁在一起,像这样, head fiename_foo && tail filename_foo.如果这还不够,您可以在。配置文件或您使用的任何登录文件:
head fiename_foo && tail filename_foo
head_and_tail() { head $1 && tail $1 }
然后,在 shell 提示符 head_and_tail filename_foo中调用它。
head_and_tail filename_foo
你可以简单地:
(head; tail) < file.txt
如果你因为某些原因需要使用管道,那么像这样:
cat file.txt | (head; tail)
注意: 如果 file.txt 中的行数小于 head 的默认行数 + tail 的默认行数,将打印重复的行。
这里的问题是面向流的程序不能预先知道文件的长度(因为如果是真正的流,可能就不会有文件长度)。
像 tail这样的工具缓冲看到的最后 n 行,等待流的结束,然后打印。
tail
如果您想在单个命令中执行此操作(并让它处理任何偏移量,如果重叠则不要重复行) ,那么您必须模仿我提到的这种行为。
试试这个:
awk -v offset=10 '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' yourfile
为什么不使用 sed完成这个任务?
sed
sed -n -e 1,+9p -e 190,+9p textfile.txt
要处理管道(流)以及文件,请将其添加到.bashrc 或.profile 文件:
headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { for (i=NR-offset+1; i<=NR; i++) print a[i] }' ; }
那么你不仅可以
headtail 10 < file.txt
还有
a.out | headtail 10
(与普通的老式 a.out | (head; tail)不同,当10超过输入的长度时,这仍然会附加虚假的空行。谢谢前面的回答)
a.out | (head; tail)
注意: headtail 10,不是 headtail -10。
headtail 10
headtail -10
对于纯流(例如来自命令的输出) ,您可以使用‘ tee’来分叉流,并将一个流发送到 head,一个流发送到 tail。这需要使用 bash (+/dev/fd/N)的“ > (list)”特性:
( COMMAND | tee /dev/fd/3 | head ) 3> >( tail )
或者使用/dev/fd/N (或/dev/stderr)加上具有复杂重定向的子 shell:
( ( seq 1 100 | tee /dev/fd/2 | head 1>&3 ) 2>&1 | tail ) 3>&1 ( ( seq 1 100 | tee /dev/stderr | head 1>&3 ) 2>&1 | tail ) 3>&1
(它们都不能在 csh 或 tcsh 中工作。)
对于控制更好一点的东西,可以使用下面的 perl 命令:
COMMAND | perl -e 'my $size = 10; my @buf = (); while (<>) { print if $. <= $size; push(@buf, $_); if ( @buf > $size ) { shift(@buf); } } print "------\n"; print @buf;'
我编写了一个简单的 Python 应用程序来完成这个任务: https://gist.github.com/garyvdm/9970522
它处理管道(流)和文件。
借鉴上述思想(经过测试的 bash & zsh)
但用的是化名“帽子”“头和尾巴”
alias hat='(head -5 && echo "^^^------vvv" && tail -5) < ' hat large.sql
基于 J.F. 塞巴斯蒂安的评论:
cat file | { tee >(head >&3; cat >/dev/null) | tail; } 3>&1
通过这种方式,您可以在一个管道中以不同的方式处理第一行和其余部分,这对于处理 CSV 数据很有用:
{ echo N; seq 3;} | { tee >(head -n1 | sed 's/$/*2/' >&3; cat >/dev/null) | tail -n+2 | awk '{print $1*2}'; } 3>&1
N*2 2 4 6
这个解决方案花费了大量的时间,似乎是唯一一个涵盖了所有用例(到目前为止)的解决方案:
command | tee full.log | stdbuf -i0 -o0 -e0 awk -v offset=${MAX_LINES:-200} \ '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset]; printf "." > "/dev/stderr" } } END { print "" > "/dev/stderr"; for(i=NR-offset+1 > offset ? NR-offset+1: offset+1 ;i<=NR;i++) { print a[i]} }'
功能列表:
(sed -u 10q; echo ...; tail) < file.txt
只是 (head;tail)主题的另一个变体,但是避免了小文件的初始缓冲区填充问题。
(head;tail)
我一直在寻找这个解决方案。我自己也试过使用 sed,但是预先不知道文件/流的长度的问题是无法解决的。在以上所有的选择中,我喜欢 Camille Goudeseune 的 awk 解决方案。他确实注意到,他的解决方案在输出中留下了额外的空行,而且数据集足够小。在这里,我提供了他的解决方案的修改,删除额外的行。
headtail() { awk -v offset="$1" '{ if (NR <= offset) print; else { a[NR] = $0; delete a[NR-offset] } } END { a_count=0; for (i in a) {a_count++}; for (i=NR-a_count+1; i<=NR; i++) print a[i] }' ; }
基于@Samus _ 解释的 给你关于@Aleksandra Zalcman 命令如何工作的内容,当你不能在不计算行数的情况下快速发现尾巴从哪里开始时,这种变化是很方便的。
{ head; echo "####################\n...\n####################"; tail; } < file.txt
或者,如果您开始使用20行以外的内容,行计数甚至可能会有所帮助。
{ head -n 18; tail -n 14; } < file.txt | cat -n
要打印文件的前10行和最后10行,您可以尝试这样做:
Cat < (head-n10 file.txt) < (tail-n10 file.txt) | less
sed -n "1,10p; $(( $(wc -l ${aFile} | grep -oE "^[[:digit:]]+")-9 )),\$p" "${aFile}"
注意 : 文件变量包含文件的 全路径。
我想说的是,根据文件的大小,主动阅读其内容可能是不可取的。在这种情况下,我认为一些简单的 shell 脚本就足够了。
下面是我最近如何处理一些非常大的 CSV 文件,我正在分析:
$ for file in *.csv; do echo "### ${file}" && head ${file} && echo ... && tail ${file} && echo; done
这会打印出每个文件的前10行和最后10行,同时还会打印出文件名和前后的省略号。
对于单个大文件,您可以简单地运行以下命令以获得相同的效果:
$ head somefile.csv && echo ... && tail somefile.csv
使用标准输入,但是很简单,并且适用于99% 的用例
#!/usr/bin/env bash COUNT=${1:-10} IT=$(cat /dev/stdin) echo "$IT" | head -n$COUNT echo "..." echo "$IT" | tail -n$COUNT
$ seq 100 | head_and_tail 4 1 2 3 4 ... 97 98 99 100
我做了一些更多的实验,主要是基于这里的建议。工作了一段时间后,我在另一个注释中找到了一些与另一个版本非常相似的内容,但是除了 stdin 之外,我更关注使用多个文件参数进行格式化。
这将很好地包装成一个脚本(暂定为 headtail)并使用 gnu awk。在 macOs 上,这可以通过 brew install gawk安装。
headtail
brew install gawk
它可以作为参数处理管道内容或文件列表。 给定文件,它打印文件名的头、头 N 行、跳过的行生成器,然后是尾 N 行。如果头部和尾部重叠或将排成一行,它既不包括跳过标记,也不显示任何重复的行。
#!/bin/bash headtail_awk() { N=10 gawk -v "n=${N}" -- '\ FNR == 1 && FILENAME != "-" { printf "\033[036m==> %s <==\033[0m\n", FILENAME; } # print head lines FNR <= n { print } # store lines in a circular buffer { a[FNR % n]=$0 } # print non-overlapping tail lines from circular buffer. ENDFILE { if ( FNR > 2 * n ) { printf "\033[0;36m>>> %s lines skipped <<<\033[0m\n", FNR - 2 * n } for (i=FNR-n+1;i<=FNR;i++) { if ( i > n) { print a[i % n] } } } ' "$@" } headtail_awk "$@"
我将把 N = 10行窗口的任何 getopts 和/或增强作为练习留给读者。
多个文件的示例输出(n = 3) :
$ headtail -n 3 /usr/share/dict/words /usr/share/dict/propernames ==> /usr/share/dict/words <== A a aa >>> 235880 lines skipped <<< zythum Zyzomys Zyzzogeton ==> /usr/share/dict/propernames <== Aaron Adam Adlai >>> 1302 lines skipped <<< Wolfgang Woody Yvonne
这招对我很管用: (head-100) < source. txt > target.txt
(head -100) < source. txt 获取 source. txt 文件的前100行,然后
Txt 将这100行代码压入一个名为 target.txt 的新文件中
起初,我认为这样的方法应该奏效: Head-100 source. txt > target.txt 但是它返回了一个空文件。