命令获取STDOUT的第n行


210

是否有任何bash命令可以让您获得STDOUT的第n行?

也就是说,某些东西

$ ls -l
-rw-r--r--@ 1 root  wheel my.txt
-rw-r--r--@ 1 root  wheel files.txt
-rw-r--r--@ 1 root  wheel here.txt

并做类似的事情

$ ls -l | magic-command 2
-rw-r--r--@ 1 root  wheel files.txt

我意识到在编写要重用的脚本时这是一种不好的做法,但是在日常使用shell时,能够以这种方式过滤我的STDOUT对我很有用。

我也意识到这将是半平凡的命令(缓冲区STDOUT,返回特定行),但是我想知道是否存在一些标准的 shell命令来执行此操作,而无需我将脚本放到适当的位置。


5
我只是投票赞成使用单词magic-command
-Sevenearths

Answers:


332

使用sed,仅用于多种用途:

ls -l | sed -n 2p

使用此替代方法看起来更有效,因为它在打印所需行时会停止读取输入,可能会在进纸过程中生成SIGPIPE,从而可能会生成不必要的错误消息:

ls -l | sed -n -e '2{p;q}'

我已经经常看到我经常使用第ls一个命令(无论如何键入它都比较容易),尽管它不是在获取SIGPIPE时会抱怨的命令。

对于一系列行:

ls -l | sed -n 2,4p

对于几行范围:

ls -l | sed -n -e 2,4p -e 20,30p
ls -l | sed -n -e '2,4p;20,30p'

p是什么意思?喜欢2p 3p?从某种意义上说,我理解这是针对2/3行的,但是其背后的理论/理解是什么?
Leo Ufimtsev '17

4
@LeoUfimtsev:这p是一条sed语句,用于打印由其前面的行范围标识的行。因此2,4p意味着打印线2,3,4
乔纳森莱弗勒

3
n手段,不打印所有其他线路
蒂莫

85
ls -l | head -2 | tail -1

13
+2,但我建议head -n 2 | tail -n 1-现代化的首尾往往会发出警告。
Michael Krelin-黑客

2
使用两个进程来过滤数据有点过大(但是,鉴于当今机器的强大功能,它们可能会应付)。泛化处理一个范围并不是一件容易的事(对于范围N..M,请使用head -n M | tail -n M-N+1),泛化处理多个范围是不可能的。
乔纳森·莱夫勒

3
头用尾巴吹成尾巴?可怕。多种更好的方法来做到这一点。
camh

16
* nix命令行的好处:一百万种方法可以做所有事情,每个人都有自己的喜好,讨厌其他所有方法... :-)

1
如何以另一种方式打印一系列行:($ ls -l | awk '{if (NR>=4 && NR<=64) print}'可以更轻松地添加更多条件,多个范围等)
user10607

41

替代漂亮的头尾方法:

ls -al | awk 'NR==2'

要么

ls -al | sed -n '2p'

1
我的awk更好,但sed很好。
Michael Krelin-黑客

不需要“如果”-请参阅黑客的回答(关于查找系统上每个文件的部分除外)。;-)
暂停,直到另行通知。

代表什么'2p'
切碎

1
@shredding简短答案打印第二行;long->使用时,在地址后仅向命令匹配模式。简要地说,当与/ p标志一起使用时,匹配的行被打印两次:sed'/ PATTERN / p'文件。当然模式是任何正则表达式
迈扎特

如果2是变量怎么办?每个示例都使用单引号,但是使用var则需要双引号。使用vars时,我们可以对awk进行“编程”以使其也使用单引号吗?实例line =1; ls | awk 'NR==$line'。我知道bash使用vars双引号。
蒂莫

21

sed1line

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

awk1line

# print line number 52
awk 'NR==52'
awk 'NR==52 {print;exit}'          # more efficient on large files

9

为了完整性;-)

较短的代码

find / | awk NR==3

寿命短

find / | awk 'NR==3 {print $0; exit}'

您不是在开玩笑!
暂停,直到另行通知。

我不是;-)实际上,我不知道为什么每个人都在使用ls-最初的问题是关于某人的STDOUT,所以我认为最好扩大它。
Michael Krelin-黑客

至少对于GNU awk而言,默认操作是{ print $0 },因此`awk'NR == 3'是一种较短的写方法。
短暂

您可能应该在该操作中添加“; exit”。当您不打算对其余的行进行任何处理时,它们将毫无意义。
卡姆(Camh)2009年

@camh:有关此问题,请参阅Jonathan Leffer的回答:“可能在馈送过程中生成SIGPIPE,这又可能生成不想要的错误消息”。
09年


6

您可以使用awk:

ls -l | awk 'NR==2'

更新资料

上面的代码由于一次失误而无法获得我们想要的:ls -l命令的第一行是总行。为此,以下修改后的代码将起作用:

ls -l | awk 'NR==3'

4

您可以轻松使用Perl吗?

$ perl -n -e 'if ($. == 7) { print; exit(0); }'

显然用7代替任何数字。


这是我的最爱,因为它似乎最容易归纳为我个人的情况,之后是 n个,perl -n -e'if($。%7 == 0){print; 退出(0); }'
mat kelcey 2012年

@matkelcey,您也可以$ awk 'NR % 7' filename打印文件中的第7行。
user10607'7

3

建议另一张海报

ls -l | head -2 | tail -1

但是如果将头插入尾巴,看起来直到N行的所有内容都会被处理两次。

将尾部管道压入头部

ls -l | tail -n +2 | head -n1

会更有效吗?


0

是的,最有效的方法(如Jonathan Leffler所指出的)是将sed与print&quit一起使用:

set -o pipefail                        # cf. help set
time -p ls -l | sed -n -e '2{p;q;}'    # only print the second line & quit (on Mac OS X)
echo "$?: ${PIPESTATUS[*]}"            # cf. man bash | less -p 'PIPESTATUS'

pipefail和PIPESTATUS的使用非常有趣,这在此页面上增加了很多。
Mike S

0

sed在我的情况下不起作用。我提议:

对于“奇数”行1,3,5,7 ... ls | awk'0 ==(NR + 1)%2'

对于“偶数”行2,4,6,8 ls | awk'0 ==(NR)%2'


-1

为了更完整。

ls -l | (for ((x=0;x<2;x++)) ; do read ; done ; head -n1)

扔掉行,直到到达第二行,然后再打印出第一行。因此,它将打印第三行。

如果只是第二行。

ls -l | (read; head -n1)

尽可能多地添加“读物”。


-1

我将此添加到我的.bash_profile中

function gdf(){
  DELETE_FILE_PATH=$(git log --diff-filter=D --summary | grep delete | grep $1 | awk '{print $4}')
  SHA=$(git log --all -- $DELETE_FILE_PATH | grep commit | head -n 1 | awk '{print $2}')
  git show $SHA -- $DELETE_FILE_PATH
}

这是有效的

gdf <file name>

我很困惑-这与问题有什么关系?
乔纳森·莱夫勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.