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
Getting head to display all but the last line of a file: command substitution and standard I/O redirection
提问by gkb0986
I have been trying to get the head
utility 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 -1
that 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 head
program 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 head
and wc
and their interaction through subshells here? Thanks for your help.
什么解释了head
和wc
以及它们通过子shell 进行交互的行为?谢谢你的帮助。
回答by dunc123
head -n -1
will give you all except the last line of its input.
head -n -1
会给你除了输入的最后一行之外的所有内容。
回答by William Pursell
head
is 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 wc
consumes all of the input and there is nothing left for head
to see. wc
inherits 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 head
tries 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 coreutils
then use the ghead
command:
假设您使用的是 Homebrew,运行brew install coreutils
然后使用ghead
命令:
cat myfile.txt | ghead -n -1
Or, equivalently:
或者,等效地:
ghead -n -1 myfile.txt
Lastly, see brew info coreutils
if you'd like to use the commands without the g
prefix (e.g., head
instead 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.txt
or echo $(($(wc -l <myfile.txt)-1))
. The problem is the way you're using it.
这有效。这太复杂了:你可以只写echo $(($(wc -l)-1)) <myfile.txt
或echo $(($(wc -l <myfile.txt)-1))
. 问题在于你使用它的方式。
cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')
wc
consumes all the input as it's counting the lines. So there is no data left to read in the pipe by the time head
is started.
wc
在计算行数时消耗所有输入。因此,在启动时管道中没有剩余的数据可供读取head
。
If your input comes from a file, you can redirect both wc
and head
from that file.
如果您的输入来自一个文件,您可以重定向wc
和head
从该文件。
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 tee
are produced at the same rate, whereas here wc
needs to fully consume its output before head
can 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 长一点。