bash 让 head 显示文件最后一行以外的所有内容:命令替换和标准 I/O 重定向

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18127726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 00:01:36  来源:igfitidea点击:

Getting head to display all but the last line of a file: command substitution and standard I/O redirection

bashunixpipe

提问by gkb0986

I have been trying to get the headutility to display all but the last line of standard input. The actual code that I needed is something along the lines of cat myfile.txt | head -n $(($(wc -l)-1)). But that didn't work. I'm doing this on Darwin/OS X which doesn't have the nice semantics of head -n -1that would have gotten me similar output.

我一直试图让该head实用程序显示除标准输入的最后一行之外的所有内容。我需要的实际代码类似于cat myfile.txt | head -n $(($(wc -l)-1)). 但这没有用。我在 Darwin/OS X 上做这件事,它没有很好的语义,head -n -1那会让我得到类似的输出。

None of these variations work either.

这些变体都不起作用。

cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')

I tested out more variations and in particular found this to work:

我测试了更多的变化,特别是发现这有效:

cat <<EOF | echo $(($(wc -l)-1))
>Hola
>Raul
>Como Esta
>Bueno?
>EOF
3

Here's something simpler that also works.

这里有一些更简单的东西也有效。

echo "hello world" | echo $(($(wc -w)+10))

This one understandably gives me an illegal line count error. But it at least tells me that the headprogram is not consuming the standard input before passing stuff on to the subshell/command substitution, a remote possibility, but one that I wanted to rule out anyway.

这个可以理解地给了我一个非法的行数错误。但它至少告诉我,head程序在将内容传递给子 shell/命令替换之前没有消耗标准输入,这是一种遥远的可能性,但无论如何我都想排除这种可能性。

echo "hello" | head -n $(cat && echo 1)

What explains the behavior of headand wcand their interaction through subshells here? Thanks for your help.

什么解释了headwc以及它们通过子shell 进行交互的行为?谢谢你的帮助。

回答by dunc123

head -n -1will give you all except the last line of its input.

head -n -1会给你除了输入的最后一行之外的所有内容。

回答by William Pursell

headis the wrong tool. If you want to see all but the last line, use:

head是错误的工具。如果您想查看除最后一行之外的所有内容,请使用:

sed $d

The reason that

原因是

# Sample of incorrect code:
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')

fails is that wcconsumes all of the input and there is nothing left for headto see. wcinherits its stdin from the subshell in which it is running, which is reading from the output of the echo. Once it consumes the input, it returns and then headtries to read the data...but it is all gone. If you want to read the input twice, the data will have to be saved somewhere.

失败是wc消耗所有输入并且没有什么head可看的。 wc从它运行的子 shell 继承它的 stdin,它从echo. 一旦它消耗了输入,它就会返回,然后head尝试读取数据……但一切都消失了。如果您想读取输入两次,则必须将数据保存在某处。

回答by devnull

Using sed:

使用 sed:

sed '$d' filename

will delete the last line of the file.

将删除文件的最后一行。

$ seq 1 10 | sed '$d' 
1
2
3
4
5
6
7
8
9

回答by Jimothy

For Mac OS X specifically, I found an answer from a comment to this Q&A.

特别是对于 Mac OS X,我从对此问答评论中找到了答案。

Assuming you are using Homebrew, run brew install coreutilsthen use the gheadcommand:

假设您使用的是 Homebrew,运行brew install coreutils然后使用ghead命令:

cat myfile.txt | ghead -n -1

Or, equivalently:

或者,等效地:

ghead -n -1 myfile.txt

Lastly, see brew info coreutilsif you'd like to use the commands without the gprefix (e.g., headinstead of ghead).

最后,看看brew info coreutils您是否想使用不带g前缀的命令(例如,head代替ghead)。

回答by Gilles 'SO- stop being evil'

cat myfile.txt | echo $(($(wc -l)-1))

This works. It's overly complicated: you could just write echo $(($(wc -l)-1)) <myfile.txtor echo $(($(wc -l <myfile.txt)-1)). The problem is the way you're using it.

这有效。这太复杂了:你可以只写echo $(($(wc -l)-1)) <myfile.txtecho $(($(wc -l <myfile.txt)-1)). 问题在于你使用它的方式。

cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')

wcconsumes all the input as it's counting the lines. So there is no data left to read in the pipe by the time headis started.

wc在计算行数时消耗所有输入。因此,在启动时管道中没有剩余的数据可供读取head

If your input comes from a file, you can redirect both wcand headfrom that file.

如果您的输入来自一个文件,您可以重定向wchead从该文件。

head -n $(($(wc -l <myfile.txt) - 1)) <myfile.txt

If your data may come from a pipe, you need to duplicate it. The usual tool to duplicate a stream is tee, but that isn't enough here, because the two outputs from teeare produced at the same rate, whereas here wcneeds to fully consume its output before headcan start. So instead, you'll need to use a single tool that can detect the last line, which is a more efficient approach anyway.

如果您的数据可能来自管道,则需要复制它。复制流的常用工具是tee,但这在这里还不够,因为来自 的两个输出tee以相同的速率产生,而这里wc需要在head开始之前完全消耗其输出。因此,您需要使用可以检测最后一行的单个工具,无论如何这是一种更有效的方法。

Conveniently, sed offers a way of matching the last line. Either printing all lines but the last, or suppressing the last output line, will work:

方便的是,sed 提供了一种匹配最后一行的方法。打印除最后一行之外的所有行,或抑制最后一行输出都可以:

sed -n '$! p'
sed '$ d'

回答by Kent

awk 'NR>1{print p}{p=##代码##}'

For this job, an awk one-liner is a bit longer than a sed one.

对于这项工作,awk one-liner 比 sed 长一点。